ایجاد حس اجزای سرور React • جاش دبلیو کومئو

مشکل این رویکرد این است که انجام همه این کارها به زمان نیاز دارد. و در حالی که همه اینها اتفاق می افتد، کاربر به یک صفحه سفید خالی خیره شده است. این مشکل با گذشت زمان بدتر میشود: هر ویژگی جدیدی که ارسال میکنیم، کیلوبایتهای بیشتری به پشته جاوا اسکریپت ما اضافه میکند و مدت زمانی را که کاربر برای نشستن و انتظار دارد افزایش میدهد.بهینهسازیهایی وجود دارند که میتوانند در اینجا کمک کنند، مانند بارگذاری تنبل ماژولهای خاص یا تقسیمبندی مبتنی بر مسیر، اما به عنوان یک قاعده کلی، بستههای JS تمایل به رشد و رشد دارند.
رندر سمت سرور برای بهبود این تجربه طراحی شده است. به جای ارسال یک فایل HTML خالی، سرور برنامه ما را به رندر می دهد تولید کند HTML واقعی کاربر یک سند HTML کاملاً تشکیل شده را دریافت می کند.
این فایل HTML همچنان شامل خواهد شد تگ کنید زیرا ما هنوز نیاز به React داریم تا روی کلاینت اجرا شود تا بتوانیم هر گونه تعاملی را مدیریت کنیم. اما ما React را به گونهای پیکربندی میکنیم که در مرورگر کمی متفاوت عمل کند: به جای اینکه همه گرههای DOM را از ابتدا ایجاد کنیم. اتخاذ می کند HTML موجود این فرآیند به عنوان شناخته شده است هیدراتاسیون
من از نحوه توضیح دن آبراموف عضو تیم اصلی React خوشم می آید:
هیدراتاسیون مانند آبیاری HTML “خشک” با “آب” تعامل و کنترل کننده رویداد است.
پس از دانلود بسته JS، React به سرعت کل برنامه ما را مرور میکند، یک طرح مجازی از UI ایجاد میکند و آن را به DOM واقعی متصل میکند، کنترلکنندههای رویداد را متصل میکند، هر گونه افکت را اجرا میکند و غیره.
بنابراین به طور خلاصه این SSR است. یک سرور HTML اولیه را تولید می کند تا کاربران مجبور نباشند در حین دانلود و تجزیه بسته های JS به یک صفحه سفید خالی نگاه کنند. سپس React سمت کلاینت از جایی که React سمت سرور متوقف شد، DOM را می پذیرد و تعامل را تزریق می کند.
بیایید در مورد واکشی داده در React صحبت کنیم. به طور معمول ما دو برنامه جداگانه داریم که از طریق شبکه ارتباط برقرار می کنند:
-
یک برنامه React سمت کلاینت
-
API REST سمت سرور
با استفاده از چیزی مانند React Query یا SWR یا Apollo، کلاینت یک درخواست شبکه به باطن ارسال میکند، که سپس دادهها را از پایگاه داده دریافت میکند و آن را از طریق شبکه ارسال میکند.
ما می توانیم این جریان را با استفاده از یک نمودار تجسم کنیم:
این یک تجسم داده است که دنباله ای از رویدادها را بین مشتری و سرور نشان می دهد. هر رویداد در اینجا به عنوان یک آیتم فهرست ارائه می شود.
- پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “دانلود کنید
جاوا اسکریپت“شامل مشتری. مدت زمان: 7 واحد از زمان - “رندرینگ
پوسته“شامل مشتری. مدت زمان: 6 واحد از زمان - درخواست به سرور. مدت زمان: 4 واحدهای زمان
- “پرس و جو پایگاه داده“شامل سرور. مدت زمان: 5 واحد از زمان
- پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “رندرینگ
محتوا“شامل مشتری. مدت زمان: 5 واحد از زمان
این نمودار اول جریان را با استفاده از استراتژی رندر سمت مشتری (CSR) نشان می دهد. با دریافت فایل HTML توسط مشتری شروع می شود. این فایل هیچ محتوایی ندارد، اما یک یا چند مورد دارد برچسب ها
هنگامی که JS دانلود و تجزیه شد، برنامه React ما اجرا میشود و دستهای از گرههای DOM ایجاد میکند و UI را پر میکند. در ابتدا، با این حال، ما چیزی از واقعی نداریم داده ها، بنابراین ما فقط می توانیم پوسته (هدر، پاورقی، طرح کلی) را با حالت بارگذاری پیش نمایش کنیم.
احتمالاً این نوع الگو را اغلب دیده اید. به عنوان مثال، UberEats با رندر کردن یک پوسته شروع میکند در حالی که دادههای مورد نیاز برای پر کردن رستورانهای واقعی را بازیابی میکند:
کاربر این وضعیت بارگیری را تا زمانی که درخواست شبکه حل و فصل شود و React دوباره ارائه شود، مشاهده میکند و رابط کاربری بارگیری را با محتوای واقعی جایگزین میکند.
بیایید به روش دیگری که می توانیم این را طراحی کنیم نگاه کنیم. این نمودار بعدی همان الگوی کلی را برای بازیابی داده ها حفظ می کند، اما استفاده می کند سرور رندر جانبی به جای رندر سمت مشتری:
این یک تجسم داده است که دنباله ای از رویدادها را بین مشتری و سرور نشان می دهد. هر رویداد در اینجا به عنوان یک آیتم فهرست ارائه می شود.
- “رندرینگ
پوسته“شامل سرور. مدت زمان: 3 واحد از زمان - پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “دانلود کنید
جاوا اسکریپت“شامل مشتری. مدت زمان: 7 واحد از زمان - “هیدراته کنید“شامل مشتری. مدت زمان: 3 واحد از زمان
- درخواست به سرور. مدت زمان: 4 واحدهای زمان
- “پرس و جو پایگاه داده“شامل سرور. مدت زمان: 5 واحد از زمان
- پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “رندرینگ
محتوا“شامل مشتری. مدت زمان: 5 واحد از زمان
در این تاپیک جدید، اولین رندر را روی سرور انجام می دهیم. یعنی کاربر یک فایل HTML دریافت می کند که کاملا خالی نیست.
این یک پیشرفت است – یک لفاف بهتر از یک صفحه سفید خالی است – اما در نهایت سوزن را به شکل قابل توجهی حرکت نمی دهد. کاربر برای دیدن صفحه بارگیری از برنامه ما بازدید نمی کند، بلکه برای دیدن به آن مراجعه می کند محتوا (رستوران ها، هتل ها، نتایج جستجو، پیام ها، هر چیز دیگری).
برای اینکه واقعاً تفاوتهای تجربه کاربر را درک کنید، بیایید برخی از معیارهای عملکرد وب را به نمودارهای خود اضافه کنیم. بین این دو جریان سوئیچ کنید و متوجه شوید که چه اتفاقی برای پرچم ها می افتد:
سرور
مشتری
این یک تجسم داده است که دنباله ای از رویدادها را بین مشتری و سرور نشان می دهد. هر رویداد در اینجا به عنوان یک آیتم فهرست ارائه می شود.
- پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “دانلود کنید
جاوا اسکریپت“شامل مشتری. مدت زمان: 7 واحد از زمان - “رندرینگ
پوسته“شامل مشتری. مدت زمان: 6 واحد از زمان - درخواست به سرور. مدت زمان: 4 واحدهای زمان
- “پرس و جو پایگاه داده“شامل سرور. مدت زمان: 5 واحد از زمان
- پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “رندرینگ
محتوا“شامل مشتری. مدت زمان: 5 واحد از زمان
هر یک از این پرچم ها نشان دهنده یک معیار عملکرد وب رایج است. در اینجا تفکیک است:
-
اول رنگ – کاربر دیگر به یک صفحه سفید خالی خیره نمی شود. طرح کلی ارائه شده است، اما محتوا هنوز وجود ندارد. گاهی اوقات به آن FCP (نقاشی اول محتوایی) می گویند.
-
صفحه تعاملی – React دانلود می شود و برنامه ما رندر/هیدراته می شود. عناصر تعاملی اکنون کاملاً قابل تنظیم هستند. گاهی اوقات به آن TTI (زمان برای تعامل) می گویند.
-
رنگ آمیزی مطالب – اکنون صفحه شامل مواردی است که کاربر را مورد علاقه خود قرار می دهد. ما داده ها را از پایگاه داده بیرون کشیدیم و در رابط کاربری ارائه کردیم. گاهی اوقات LCP (بزرگترین رنگ محتوایی) نامیده می شود.
با انجام رندر اولیه روی سرور، می توانیم این “پوسته” اولیه را سریعتر ترسیم کنیم. این می تواند باعث شود بارگیری کمی سریعتر احساس شود زیرا حس پیشرفت را در مورد اتفاقات در حال رخ دادن ایجاد می کند.
و در برخی شرایط این خواهد شد یک پیشرفت قابل توجه باشد. به عنوان مثال، ممکن است کاربر فقط منتظر بارگیری هدر باشد تا بتواند روی پیوند ناوبری کلیک کند.
اما آیا این جریان برای شما کمی احمقانه به نظر نمی رسد؟ وقتی به نمودار SSR نگاه می کنم، نمی توانم متوجه این درخواست شوم آغاز می شود روی سرور به جای نیاز به درخواست شبکه دو طرفه دوم، چرا پایگاه داده کار نمی کند در طول این درخواست اولیه؟
به عبارت دیگر، چرا کاری مشابه انجام نمی دهید؟
سرور
مشتری
این یک تجسم داده است که دنباله ای از رویدادها را بین مشتری و سرور نشان می دهد. هر رویداد در اینجا به عنوان یک آیتم فهرست ارائه می شود.
- “پرس و جو پایگاه داده“شامل سرور. مدت زمان: 5 واحد از زمان
- “رندرینگ
برنامه“شامل سرور. مدت زمان: 6 واحد از زمان - پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- “دانلود کنید
جاوا اسکریپت“شامل مشتری. مدت زمان: 7 واحد از زمان - “هیدراته کنید“شامل مشتری. مدت زمان: 3 واحد از زمان
به جای اینکه بین کلاینت و سرور به عقب و جلو پرش کنیم، درخواست خود را به پایگاه داده به عنوان بخشی از درخواست اولیه ارسال می کنیم و رابط کاربری کاملاً پر شده را مستقیماً برای کاربر ارسال می کنیم.
اما اوم، دقیقاً چگونه این کار را انجام دهیم؟
برای اینکه این کار انجام شود، باید بتوانیم بخشی از کدهایی را که React اجرا میکند، بدهیم فوق العاده روی سرور برای ایجاد پرس و جو پایگاه داده. اما این یک گزینه با React نبود… حتی با رندر سمت سرور، همه اجزای ما در هر دو سرور و مشتری
اکوسیستم راه حل های زیادی برای این مشکل ارائه کرده است. “متا چارچوب” چارچوبی است که بر روی React ساخته می شود و ویژگی های اضافی مانند مسیریابی یا مدیریت داده را اضافه می کند. مانند Next.js و Gatsby راه خود را برای اجرای کد منحصراً بر روی سرور ایجاد کرده اند.
برای مثال، در اینجا به نظر می رسد که با استفاده از Next.js (با استفاده از روتر قدیمی Pages):
import db from 'imaginary-db';
// This code only runs on the server:
export async function getServerSideProps() {
const link = db.connect('localhost', 'root', 'passw0rd');
const data = await db.query(link, 'SELECT * FROM products');
return {
props: { data },
};
}
// This code runs on the server + on the client
export default function Homepage({ data }) {
return (
h1>Trending Productsh1>
{data.map((item) => (
article key={item.id}>
h2>{item.title}h2>
p>{item.description}p>
article>
))}
>
);
}
بیایید این را تجزیه کنیم: وقتی سرور درخواستی را دریافت می کند، getServerSideProps تابع نامیده می شود. برمیگرداند a props شی سپس این پروپ ها به کامپوننت هدایت می شوند که ابتدا روی سرور رندر می شود و سپس روی کلاینت رندر می شود.
نکته هوشمندانه اینجاست که getServerSideProps روی مشتری تکرار نشود در واقع، این ویژگی حتی در بسته های جاوا اسکریپت ما گنجانده نشده است!
این رویکرد بود عالی جلوتر از زمان خود راستش عالیه اما آنجا هستند برخی از معایب با این:
-
این استراتژی فقط در سطح مسیر، برای اجزای بالای درخت کار می کند. ما نمی توانیم این کار را در هیچ جزء انجام دهیم.
-
هر متا چارچوب رویکرد خاص خود را ارائه کرده است. Next.js یک رویکرد دارد، گتسبی رویکردی دیگر، ریمیکس رویکرد دیگری دارد. استاندارد نیست.
-
همه اجزای React ما این کار را خواهند کرد همیشه به مشتری حتی زمانی که نیازی ندارد آب دهید.
تیم React سال هاست که بی سر و صدا با این مشکل دست به گریبان بوده و سعی می کند راهی رسمی برای حل این مشکل ارائه دهد. راه حل آنها نامیده می شود اجزای سرور React.
در سطح بالا، اجزای سرور React نام یک پارادایم کاملاً جدید است. در این دنیای جدید، ما می توانیم اجزای کاری ایجاد کنیم منحصرا بر روی سرور. این به ما امکان می دهد کارهایی مانند نوشتن پرس و جوهای پایگاه داده را درست در کامپوننت های React خود انجام دهیم!
در اینجا یک مثال سریع از “مولفه سرور” آورده شده است:
import db from 'imaginary-db';
async function Homepage() {
const link = db.connect('localhost', 'root', 'passw0rd');
const data = await db.query(link, 'SELECT * FROM products');
return (
h1>Trending Productsh1>
{data.map((item) => (
article key={item.id}>
h2>{item.title}h2>
p>{item.description}p>
article>
))}
>
);
}
export default Homepage;
به عنوان فردی که سال ها از React استفاده می کند، این کد به نظر می رسد کاملا وحشی در ابتدا به من 😅
“اما صبر کن!” غرایز من فریاد زد “کامپوننت های کاربردی نمی توانند ناهمزمان باشند! و ما اجازه نداریم مستقیماً در چنین رندرهایی عوارض جانبی داشته باشیم!”
نکته اصلی برای درک این است: اجزای سرور هرگز دوباره ارائه نمی شوند. فرار می کنند یک بار روی سرور برای تولید رابط کاربری. مقدار رندر شده برای مشتری ارسال می شود و در جای خود قفل می شود. تا آنجا که به React مربوط می شود، این خروجی تغییرناپذیر است و هرگز تغییر نخواهد کرد.حداقل تا زمانی که اتفاقی در سطح روتر رخ ندهد، مانند پیمایش به یک صفحه جدید.
این بدان معناست که الف یک قطعه بزرگ React API با اجزای سرور ناسازگار است. به عنوان مثال، ما نمی توانیم از حالت استفاده کنیم زیرا وضعیت می تواند تغییر کند، اما اجزای سرور نمی توانند دوباره ارائه شوند. و ما نمی توانیم از افکت ها استفاده کنیم زیرا افکت ها خود به خود اجرا می شوند بعد از رندر کلاینت و اجزای سرور هرگز به مشتری نمی رسند.
همچنین به این معنی است که در مورد قوانین کمی انعطاف پذیری بیشتری داریم. به عنوان مثال، در React سنتی باید عوارض جانبی را داخل a قرار دهیم useEffect callback یا رویداد handler یا چیزی شبیه به آن تا در هر رندر تکرار نشود. اما اگر کامپوننت فقط کار کند یک بار، لازم نیست نگران آن باشیم!
اجزای سرور خودت بهطور شگفتانگیزی ساده هستند، اما پارادایم «React Server Components» بسیار پیچیدهتر است. به این دلیل است که ما من هنوز دارم اجزای ساده قدیمی و نحوه قرار گرفتن آنها با هم می تواند بسیار گیج کننده باشد.
در این پارادایم جدید، اجزای React “سنتی” که با آنها آشنا هستیم نامیده می شوند اجزای مشتری. راستش را بخواهید این اسم را دوست ندارم. 😅
نام “مولفه مشتری” دلالت بر این دارد که این اجزا فقط به مشتری نشان می دهد، اما این در واقع درست نیست. اجزای مشتری مطابق با مشتری ارائه می شود و سرور
من می دانم که همه این اصطلاحات بسیار گیج کننده است، بنابراین در اینجا چگونه آن را خلاصه می کنم:
-
اجزای سرور React نام این پارادایم جدید است.
-
در این پارادایم جدید، مؤلفههای «استاندارد» React که ما میشناسیم و دوست داریم به عنوان اجزای مشتری. این یک نام جدید برای یک چیز قدیمی است.
-
این پارادایم جدید نوع جدیدی از مؤلفه را معرفی می کند، اجزای سرور. این اجزای جدید به طور انحصاری بر روی سرور ارائه می شوند. کد آنها در بسته JS گنجانده نشده است و بنابراین هرگز هیدراته یا رندر نمی شوند.
پیوند به این عنوانمحیط های سازگار
بنابراین معمولاً وقتی یک ویژگی React جدید منتشر میشود، میتوانیم با فشار دادن وابستگی React خود به آخرین نسخه، از آن در پروژههای موجود خود استفاده کنیم. به سرعت npm install react@latest و ما به مسابقات می رویم.
متأسفانه React Server Components اینطور کار نمی کند.
درک من این است که مؤلفههای سرور React باید به شدت با تعدادی از چیزهای خارج از React یکپارچه شوند، مواردی مانند بسته، سرور و روتر.
همانطور که من این را می نویسم، تنها یک راه برای شروع استفاده از React Server Components وجود دارد، و آن استفاده از Next.js 13.4+ با استفاده از معماری جدید “App Router” است.
امیدواریم در آینده چارچوبهای مبتنی بر React بیشتری شامل اجزای سرور React شوند. احساس ناخوشایندی است که یک ویژگی اصلی React فقط در یک ابزار خاص در دسترس است! React Docs دارای “مدرن ترین فریم ورک ها” است بخش(در برگه جدید باز می شود) جایی که آنها چارچوب هایی را که از React Server Components پشتیبانی می کنند لیست می کنند. من قصد دارم هر از چند گاهی این صفحه را بررسی کنم تا ببینم آیا گزینه های جدیدی وجود دارد یا خیر.
پیوند به این عنوانتنظیم اجزای مشتری
در این پارادایم جدید “React Server Components” فرض بر این است که تمام کامپوننت ها به طور پیش فرض اجزای سرور هستند. ما باید برای اجزای مشتری “انتخاب” کنیم.
ما این کار را با مشخص کردن یک نام تجاری جدید انجام می دهیم بخشنامه:
'use client';
import React from 'react';
function Counter() {
const [count, setCount] = React.useState(0);
return (
button onClick={() => setCount(count + 1)}>
Current value: {count}
button>
);
}
export default Counter;
این تک رشته در بالا، 'use client'، به این صورت است که به React سیگنال می دهیم که مؤلفه(های) این فایل مؤلفه های مشتری هستند، که باید در بسته های JS ما گنجانده شوند تا بتوان آنها را مجدداً در کلاینت رندر کرد.
که می تواند به نظر می رسد به عنوان یک روش فوقالعاده عجیب برای تعیین نوع مؤلفهای که ایجاد میکنیم، اما سابقهای برای مواردی مانند این وجود دارد: “استفاده از سختگیر”(در برگه جدید باز می شود) دستورالعملی که شامل “حالت سخت” در جاوا اسکریپت است.
ما مشخص نمی کنیم 'use server' دستورالعمل در اجزای سرور ما؛ در پارادایم React Server Components، اجزا به طور پیش فرض به عنوان اجزای سرور در نظر گرفته می شوند. در واقع 'use server' برای اقدامات سرور استفاده می شود، یک عملکرد کاملا متفاوت که خارج از محدوده این پست وبلاگ است.
یکی از اولین سوالاتی که هنگام معرفی React Server Components داشتم این بود: چه اتفاقی می افتد زمانی که پایه ها تعویض می شوند؟
به عنوان مثال، فرض کنید ما یک جزء سرور مانند این داریم:
function HitCounter({ hits }) {
return (
div>
Number of hits: {hits}
div>
);
}
فرض کنید در رندر اولیه سمت سرور، hits برابر بود با 0. سپس این مؤلفه نشانه گذاری زیر را ایجاد می کند:
div>
Number of hits: 0
div>
اما چه اتفاقی می افتد اگر ارزش hits تغییرات؟ فرض کنید یک متغیر حالت است و از آن تغییر می کند 0 به 1. HitCounter باید دوباره رندر شود، اما این من نمی توانم رندر مجدد چون یک جزء سرور است!
مسئله این است که اجزای سرور واقعاً به تنهایی معنی ندارند. ما باید بزرگنمایی کنیم تا نمای کلی تری داشته باشیم، به ساختار برنامه خود نگاه کنیم.
فرض کنید درخت مؤلفه زیر را داریم:
اگر همه این مؤلفه ها اجزای سرور باشند، پس همه چیز منطقی است. هیچ یک از اجزاء هرگز تغییر نمی کند زیرا هیچ یک از اجزاء هرگز دوباره رندر نمی شوند.
اما فرض کنید که Article جزء مالک است hits متغیر حالت برای استفاده از state، باید آن را به یک جزء مشتری تبدیل کنیم:
آیا مشکل را اینجا می بینید؟ چه زمانی Article رندر مجدد، تمام اجزای متعلق به این کار انجام خواهند داد بیش از حد رندر مجدد شامل HitCounter و Discussion. با این حال، اگر اینها اجزای سرور هستند، آنها هستند من نمی توانم تصویربرداری مجدد
برای جلوگیری از این وضعیت غیرممکن، تیم React یک قانون اضافه کرد: اجزای سرویس گیرنده فقط می توانند سایر اجزای مشتری را وارد کنند. این 'use client' بخشنامه به این معناست که این موارد از HitCounter و Discussion باید به اجزای مشتری تبدیل شوند.
یکی از بزرگترین لحظات آها من با React Server Components این بود که متوجه شدم این پارادایم جدید تماماً در مورد ایجاد است. مرزهای مشتری. این چیزی است که در عمل اتفاق می افتد:
وقتی اضافه می کنیم 'use client' بخشنامه به Article جزء، ما یک “مرز مشتری” ایجاد می کنیم. همه اجزا در این حد هستند به طور ضمنی به اجزای مشتری تبدیل می شود. اگرچه اجزای آن دوست دارند HitCounter من ندارم 'use client' دستورالعمل، آنها همچنان در آن موقعیت خاص به مشتری هیدراته/ارائه می کنند.کامپوننت HitCounter همچنان می تواند در موقعیت های دیگر به عنوان یک مؤلفه سرور ارائه شود، اگر در جای دیگری از یک مؤلفه سرور وارد شود.
یعنی نیازی نیست اضافه کنیم 'use client' به هر فایلی که روی کلاینت اجرا شود. در عمل، فقط زمانی نیاز داریم که آن را اضافه کنیم که مرزهای مشتری جدید ایجاد کنیم.
پیوند به این عنوانراه حل ها
وقتی برای اولین بار فهمیدم که اجزای سرویس گیرنده نمی توانند مؤلفه های سرور را ارائه دهند، آن را کاملاً محدود کردم. اگر من نیاز به استفاده از حالت بالا در برنامه داشته باشم چه می شود؟ آیا این بدان معنی است همه چیز باید جزء مشتری بشه؟؟
به نظر می رسد که در بسیاری از موارد ما می توانیم با تغییر ساختار برنامه خود، این محدودیت را برطرف کنیم مالک تغییر می کند.
توضیح این موضوع سخت است، بنابراین از یک مثال استفاده می کنیم:
'use client';
import { DARK_COLORS, LIGHT_COLORS } from '@/constants.js';
import Header from './Header';
import MainContent from './MainContent';
function Homepage() {
const [colorTheme, setColorTheme] = React.useState('light');
const colorVariables = colorTheme === 'light'
? LIGHT_COLORS
: DARK_COLORS;
return (
body style={colorVariables}>
Header />
MainContent />
body>
);
}
در این تنظیمات ما باید از React State استفاده کنیم تا به کاربران اجازه دهیم بین حالت تاریک / حالت روشن جابجا شوند. این باید در بالای درخت برنامه اتفاق بیفتد تا بتوانیم توکن های متغیر CSS خود را روی آن اعمال کنیم tag.
In order to use state, we need to make Homepage جزء مشتری و از آنجایی که این بالای برنامه ما است، به این معنی است که تمام اجزای دیگر - Header و MainContent - همچنین به طور ضمنی به اجزای مشتری تبدیل خواهد شد.
برای رفع این مشکل، بیایید موارد مدیریت رنگ را به جزء خودش که به فایل خودش منتقل شده است، در نظر بگیریم:
// /components/ColorProvider.js
'use client';
import { DARK_COLORS, LIGHT_COLORS } from '@/constants.js';
function ColorProvider({ children }) {
const [colorTheme, setColorTheme] = React.useState('light');
const colorVariables = colorTheme === 'light'
? LIGHT_COLORS
: DARK_COLORS;
return (
body style={colorVariables}>
{children}
body>
);
}
بازگشت به Homepage، ما از این کامپوننت جدید به صورت زیر استفاده می کنیم:
// /components/Homepage.js
import Header from './Header';
import MainContent from './MainContent';
import ColorProvider from './ColorProvider';
function Homepage() {
return (
ColorProvider>
Header />
MainContent />
ColorProvider>
);
}
می توانیم حذف کنیم 'use client' بخشنامه از Homepage زیرا دیگر از حالت یا سایر ویژگی های React سمت کلاینت استفاده نمی کند. این به این معنی است که Header و MainContent دیگر به طور ضمنی به اجزای مشتری تبدیل نمی شود!
اما یک دقیقه صبر کنید. ColorProviderمولفه مشتری، a است پدر و مادر به Header و MainContent. در هر صورت، هنوز بالاتر از درخت است، درست است؟
با این حال، وقتی صحبت از مرزهای مشتری می شود، رابطه والدین/فرزند اهمیتی ندارد. Homepage واردات و رندر است Header و MainContent. این به این معنی است که Homepage تصمیم می گیرد الزامات چیست برای این مولفه ها
به یاد داشته باشید که مشکلی که ما سعی در حل آن داریم این است که اجزای سرور نمی توانند دوباره ارائه شوند و بنابراین نمی توان مقادیر جدیدی برای هیچ یک از ویژگی های آنها به آنها داد. با این تنظیمات جدید، Homepage تصمیم می گیرد که تکیه گاه برای چیست Header و MainContent، و از آن زمان تاکنون Homepage یک جزء سرور است، مشکلی نیست.
این چیزهای غم انگیز است حتی پس از سالها تجربه React، من هنوز این موضوع را بسیار گیجکننده میدانم. برای ایجاد شهود برای این کار کمی تمرین لازم بود.
به بیان دقیق تر، 'use client' دستورالعمل در سطح فایل/ماژول کار می کند. هر ماژول وارداتی یک فایل کامپوننت کلاینت باید شامل اجزای کلاینت نیز باشد. وقتی مدیر گروه کد ما را ادغام می کند، در نهایت این واردات را دنبال می کند!
بیایید در سطح کمی پایین تر به این موضوع نگاه کنیم. وقتی از یک کامپوننت سرور استفاده می کنیم، خروجی آن چگونه است؟ در واقع چه چیزی تولید می شود؟
بیایید با یک برنامه فوق العاده ساده React شروع کنیم:
function Homepage() {
return (
p>
Hello world!
p>
);
}
در پارادایم React Server Components، همه اجزا به طور پیش فرض جزء سرور هستند. از آنجایی که ما این مؤلفه را بهصراحت بهعنوان مؤلفه کلاینت علامتگذاری نکردهایم (یا آن را در محدودههای کلاینت ارائه نکردهایم)، این مؤلفه فقط در سرور ارائه میشود.
هنگامی که از این برنامه در مرورگر بازدید می کنیم، یک سند HTML به شکل زیر دریافت می کنیم:
DOCTYPE html>
html>
body>
p>Hello world!p>
script src="/static/js/bundle.js">script>
script>
self.__next['$Homepage-1'] = {
type: 'p',
props: null,
children: "Hello world!",
};
script>
body>
html>
We see that our HTML document includes the UI generated by our React application, the “Hello world!” paragraph. This is thanks to Server Side Rendering, and isn't directly attributable to React Server Components.
Below that, we have a برچسبی که بسته JS ما را بارگیری می کند. این بسته شامل وابستگی هایی مانند React و همچنین تمام مؤلفه های مشتری مورد استفاده در برنامه ما است. و از آنجایی که ما Homepage جزء یک مؤلفه سرور است، کد این مؤلفه است نه در این بسته گنجانده شده است.
بالاخره دومی داریم برچسب با تعدادی JS تعبیه شده:
self.__next['$Homepage-1'] = {
type: 'p',
props: null,
children: "Hello world!",
};
این چیزی است که واقعا جالب است. اساساً، کاری که ما اینجا انجام می دهیم این است که به React می گوییم: «هی، پس می دانم که دلت برای من تنگ شده است. Homepage کد مؤلفه، اما نگران نباشید: این چیزی است که آن را ارائه می دهد.
به طور معمول، زمانی که React مشتری را هیدراته می کند، به سرعت تمام اجزا را رندر می کند و یک نمایش مجازی از برنامه ایجاد می کند. نمی تواند این کار را برای اجزای سرور انجام دهد زیرا کد در بسته JS گنجانده نشده است.
بنابراین ما مقدار رندر شده را ارسال می کنیم، نمایش مجازی که توسط سرور تولید می شود. زمانی که React روی کلاینت بارگذاری میشود، بهجای تولید مجدد از این توضیحات استفاده مجدد میکند.
این اجازه می دهد ColorProvider مثال بالا برای کار کردن خروج از Header و MainContent در منتقل می شود ColorProvider جزء از طریق children پشتیبانی کنید ColorProvider می تواند هر چقدر که بخواهد دوباره رندر کند، اما این داده ها ثابت هستند و توسط سرور قفل شده اند.
این انجام می دهد به این معنی است که با کوچکتر شدن بسته های JS ما، فایل HTML بزرگتر می شود. به جای داشتن مولفه تعریف در فایل JS کامپوننت ها را داریم ارزش بازگشتی تعبیه شده در a برچسب زدن به طور متوسط، ما همچنان داده های کلی کمتری را از طریق شبکه ارسال خواهیم کرد، اما لازم به یادآوری است که اجزای سرور اینگونه نیستند. به طور کامل به صورت رایگان همچنین باید توجه داشته باشم که فایل HTML تقسیم و پخش می شود، بنابراین مرورگر همچنان می تواند بدون نیاز به منتظر ماندن برای همه چیزهای مزخرف، رابط کاربری را به سرعت ترسیم کند. برچسب زدن
اگر کنجکاو هستید ببینید درست است نمایش هایی از نحوه سریال سازی و ارسال اجزای سرور از طریق شبکه، به RSC مراجعه کنید ابزار توسعه(در برگه جدید باز می شود) توسط توسعه دهنده Alvar Lagerlöf.
React Server Components اولین راه "رسمی" برای اجرای کد سرور انحصاری در React است. همانطور که قبلاً اشاره کردم، اما اینطور نیست در واقع یک چیز جدید در اکوسیستم گسترده تر React. ما از سال 2016 توانستیم کدهای اختصاصی سرور را در Next.js اجرا کنیم!
تفاوت بزرگ این است که ما قبلاً هرگز راهی برای اجرای کدهای انحصاری سرور نداشته ایم داخل اجزای ما
واضح ترین مزیت بهره وری است. مؤلفههای سرور در بستههای JS ما گنجانده نشدهاند، که این امر باعث کاهش مقدار جاوا اسکریپت مورد نیاز برای دانلود و تعداد مؤلفههایی میشود که باید هیدراته شوند:
سرور
مشتری
این یک تجسم داده است که دنباله ای از رویدادها را بین مشتری و سرور نشان می دهد. هر رویداد در اینجا به عنوان یک آیتم فهرست ارائه می شود.
- "پرس و جو پایگاه داده"شامل سرور. مدت زمان: 5 واحد از زمان
- "رندرینگ
برنامه"شامل سرور. مدت زمان: 6 واحد از زمان - پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- "دانلود کنید
جاوا اسکریپت"شامل مشتری. مدت زمان: 7 واحد از زمان - "هیدراته کنید"شامل مشتری. مدت زمان: 3 واحد از زمان
با این حال، این احتمالاً کمترین هیجان برای من است. راستش اکثر برنامه های Next.js اینطوری هستند در حال حاضر وقتی نوبت به زمان تعامل با صفحه می رسد، به اندازه کافی سریع است.
اگر از اصول HTML معنایی پیروی کنید، بیشتر برنامه شما باید حتی قبل از هیدراته شدن React کار کند. پیوندها را می توان دنبال کرد، فرم ها را می توان ارسال کرد، آکاردئون ها را می توان گسترش داد و جمع کرد (با استفاده از
). برای اکثر پروژه ها، اگر چند ثانیه طول بکشد تا React هیدراته شود، خوب است.
اما اینجا چیزی است که به نظر من واقعا جالب است: ما دیگر مجبور نیستیم در مورد ویژگی ها در مقابل اندازه بسته، مصالحه های مشابهی انجام دهیم!
به عنوان مثال، اکثر وبلاگ های فنی به نوعی کتابخانه برجسته نحوی نیاز دارند. من از پریسم در این وبلاگ استفاده می کنم. تکه کدها به شکل زیر هستند:
function exampleJavaScriptFunction(param) {
return "Hello world!"
}
یک کتابخانه برجسته نحوی مناسب، با پشتیبانی از همه زبانهای برنامهنویسی محبوب، چندین مگابایت خواهد بود که برای جا دادن در یک بسته JS بسیار بزرگ است. در نتیجه، ما باید با قطع زبانها و ویژگیهایی که مأموریت حیاتی نیستند، مصالحه کنیم.
اما فرض کنید نحو را روشن می کنیم در یک جزء سرور در این حالت، هیچ یک از کدهای کتابخانه واقعاً در بستههای JS ما گنجانده نمیشود. در نتیجه، ما مجبور به مصالحه نخواهیم بود، میتوانیم از همه زنگها و سوتها استفاده کنیم.
این ایده بزرگ پشت آن است روشن(در برگه جدید باز می شود)، یک بسته برجسته نحوی مدرن که برای کار با React Server Components طراحی شده است.
این چیزی است که من را در مورد React Server Components هیجان زده می کند. مواردی که گنجاندن آنها در بسته JS بسیار گران است، اکنون می توانند روی سرور اجرا شوند رایگان، اضافه کردن صفر کیلوبایت به بسته های ما و ایجاد تجربه کاربری بهتر.
این فقط در مورد عملکرد و UX نیست. پس از مدتی کار با RSC، من واقعاً درک کردم که اجزای سرور چقدر آسان هستند. ما هرگز نباید نگران آرایههایی با وابستگیها، بسته شدن قدیمی، حافظهگذاری یا سایر پیچیدگیهای ناشی از چیزها تغییر می کند
بالاخره هنوز خیلی زود است. اجزای React Server تنها چند ماه پیش از نسخه بتا خارج شدند! من واقعاً هیجان زده هستم که ببینم در چند سال آینده چگونه اوضاع پیشرفت می کند زیرا جامعه همچنان به نوآوری راه حل های جدید مانند Bright با استفاده از این الگوی جدید ادامه می دهد. زمان هیجان انگیزی برای توسعه دهنده React است!
React Server Components یک توسعه هیجان انگیز است، اما در واقع تنها بخشی از پازل "Modern React" است.
اتفاقاتی می افتد در واقع زمانی که ما React Server Components را با Suspense و معماری Streaming SSR جدید ترکیب کنیم، جالب است. این به ما این امکان را می دهد وحشی چیزهایی مانند این:
سرور
مشتری
این یک تجسم داده است که دنباله ای از رویدادها را بین مشتری و سرور نشان می دهد. هر رویداد در اینجا به عنوان یک آیتم فهرست ارائه می شود.
- "رندر شل"شامل سرور. مدت زمان: 3 واحد از زمان
- پاسخ از سرور. مدت زمان: 3 واحدهای زمان
- "پایگاه داده
استعلام"شامل سرور. مدت زمان: 8 واحد از زمان - "رندرینگ
محتوا"شامل سرور. مدت زمان: 3 واحد از زمان - پاسخ از سرور. مدت زمان: 4 واحدهای زمان
- "JS را دانلود کنید"شامل مشتری. مدت زمان: 5 واحد از زمان
- "هیدراته کنید"شامل مشتری. مدت زمان: 2 واحد از زمان
- "هیدراته کنید"شامل مشتری. مدت زمان: 2 واحد از زمان
این فراتر از محدوده این آموزش است، اما می توانید در مورد این معماری بیشتر بدانید Github(در برگه جدید باز می شود).
این نیز چیزی است که ما در دوره جدید من، The Joy of، به طور عمیق بررسی می کنیم واکنش نشان دهید(در برگه جدید باز می شود). من می خواهم کمی بیشتر در مورد آن به شما بگویم اگر اشکالی ندارد! ❤️
Joy of React یک دوره آموزشی تعاملی و مبتدی است که برای کمک به شما در ایجاد شهود در مورد نحوه عملکرد React طراحی شده است. ما از پایه شروع می کنیم (بدون نیاز به تجربه قبلی React) و راه خود را از طریق برخی از سخت ترین جنبه های React طی می کنیم.
این دوره تقریباً دو سال است که تمرکز تمام وقت من بوده است و شامل همه مهم ترین چیزهایی است که در بیش از 10 سال تجربه در مورد React یاد گرفته ام.
خیلی چیزهای خوب هست که دوست دارم به شما بگویم. علاوه بر خود React و تمام مواردی که در این پست وبلاگ به آنها اشاره کردیم، با بخش های مورد علاقه من در اکوسیستم React آشنا خواهید شد. به عنوان مثال، شما یاد خواهید گرفت که چگونه با استفاده از Framer Motion، انیمیشن های چیدمان سطح بعدی بسازید:
در اینجا می توانید اطلاعات بیشتری در مورد دوره کسب کنید:
React Server Components یک تغییر پارادایم مهم است. من شخصا هستم عالی ما مشتاقیم تا ببینیم که در چند سال آینده اوضاع چگونه پیش خواهد رفت زیرا اکوسیستم ابزارهای بیشتری مانند Bright می سازد که از اجزای سرور استفاده می کند.
من احساس می کنم که ساختمان در React در شرف سردتر شدن است. 😄
آخرین به روز رسانی از
9 مه 2025


