فارسی

با آب‌رسانی انتخابی React 18، عملکرد وب سریع‌تری را تجربه کنید. این راهنمای جامع، بارگذاری مبتنی بر اولویت، رندرینگ جریانی سمت سرور (SSR) و پیاده‌سازی عملی را برای مخاطبان جهانی بررسی می‌کند.

آب‌رسانی انتخابی در React: نگاهی عمیق به بارگذاری کامپوننت‌ها بر اساس اولویت

در تلاش بی‌وقفه برای دستیابی به عملکرد برتر وب، توسعه‌دهندگان فرانت‌اند دائماً در حال مدیریت یک بده‌بستان پیچیده هستند. ما برنامه‌هایی غنی و تعاملی می‌خواهیم، اما در عین حال نیاز داریم که این برنامه‌ها بدون توجه به دستگاه یا سرعت شبکه کاربر، فوراً بارگذاری شوند و بدون تأخیر پاسخ دهند. سال‌هاست که رندرینگ سمت سرور (SSR) سنگ بنای این تلاش بوده و بارگذاری اولیه سریع صفحات و مزایای قوی SEO را به ارمغان آورده است. با این حال، SSR سنتی با یک تنگنای قابل توجه همراه بود: مشکل هولناک آب‌رسانی «همه یا هیچ».

پیش از آنکه یک صفحه تولید شده با SSR بتواند واقعاً تعاملی شود، کل باندل جاوا اسکریپت برنامه باید دانلود، تجزیه و اجرا می‌شد. این امر اغلب منجر به یک تجربه کاربری ناامیدکننده می‌شد که در آن صفحه کامل و آماده به نظر می‌رسید اما به کلیک‌ها یا ورودی‌ها پاسخ نمی‌داد؛ پدیده‌ای که بر معیارهای کلیدی مانند زمان تا تعامل (TTI) و معیار جدیدتر تعامل تا رنگ بعدی (INP) تأثیر منفی می‌گذارد.

اینجا بود که React 18 وارد شد. با موتور رندرینگ همزمان پیشگامانه‌اش، React راه‌حلی را معرفی کرد که به همان اندازه که قدرتمند است، زیبا نیز هست: آب‌رسانی انتخابی (Selective Hydration). این فقط یک بهبود تدریجی نیست؛ بلکه یک تغییر پارادایم اساسی در نحوه زنده شدن برنامه‌های React در مرورگر است. این مدل از مدل آب‌رسانی یکپارچه فراتر رفته و به یک سیستم دانه‌بندی شده و مبتنی بر اولویت تبدیل شده است که تعامل کاربر را در اولویت قرار می‌دهد.

این راهنمای جامع به بررسی مکانیک، مزایا و پیاده‌سازی عملی آب‌رسانی انتخابی React خواهد پرداخت. ما نحوه کارکرد آن را تشریح خواهیم کرد، دلیل اینکه چرا این یک تغییردهنده بازی برای برنامه‌های جهانی است و چگونه می‌توانید از آن برای ساختن تجربیات کاربری سریع‌تر و انعطاف‌پذیرتر استفاده کنید.

درک گذشته: چالش آب‌رسانی سنتی SSR

برای درک کامل نوآوری آب‌رسانی انتخابی، ابتدا باید محدودیت‌هایی را که برای غلبه بر آن‌ها طراحی شده است، درک کنیم. بیایید به دنیای رندرینگ سمت سرور قبل از React 18 بازگردیم.

رندرینگ سمت سرور (SSR) چیست؟

در یک برنامه React معمولی که در سمت کلاینت رندر می‌شود (CSR)، مرورگر یک فایل HTML حداقلی و یک باندل بزرگ جاوا اسکریپت دریافت می‌کند. سپس مرورگر جاوا اسکریپت را برای رندر کردن محتوای صفحه اجرا می‌کند. این فرآیند می‌تواند کند باشد و کاربران را در حالی که به یک صفحه خالی خیره شده‌اند رها کند و ایندکس کردن محتوا را برای خزنده‌های موتورهای جستجو دشوار سازد.

SSR این مدل را معکوس می‌کند. سرور برنامه React را اجرا کرده، HTML کامل صفحه درخواستی را تولید و آن را به مرورگر ارسال می‌کند. مزایا فوری هستند:

تنگنای آب‌رسانی «همه یا هیچ»

در حالی که HTML اولیه از SSR یک پیش‌نمایش سریع غیرتعاملی ارائه می‌دهد، صفحه هنوز واقعاً قابل استفاده نیست. کنترل‌کننده‌های رویداد (مانند `onClick`) و مدیریت وضعیت تعریف شده در کامپوننت‌های React شما وجود ندارند. فرآیند اتصال این منطق جاوا اسکریپت به HTML تولید شده در سرور، آب‌رسانی (hydration) نامیده می‌شود.

مشکل کلاسیک در اینجا نهفته است: آب‌رسانی سنتی یک عملیات یکپارچه، همزمان و مسدودکننده بود. این فرآیند یک توالی سخت و نابخشودنی را دنبال می‌کرد:

  1. کل باندل جاوا اسکریپت برای کل صفحه باید دانلود شود.
  2. React باید کل باندل را تجزیه و اجرا کند.
  3. سپس React کل درخت کامپوننت را از ریشه پیمایش کرده، شنوندگان رویداد را متصل و وضعیت را برای تک تک کامپوننت‌ها تنظیم می‌کند.
  4. تنها پس از تکمیل این فرآیند کامل، صفحه تعاملی می‌شود.

تصور کنید یک ماشین جدید، زیبا و کاملاً مونتاژ شده دریافت کرده‌اید، اما به شما گفته می‌شود تا زمانی که یک کلید اصلی برای کل سیستم الکترونیکی خودرو فعال نشود، نمی‌توانید حتی یک در را باز کنید، موتور را روشن کنید یا حتی بوق بزنید. حتی اگر فقط بخواهید کیفتان را از صندلی شاگرد بردارید، باید منتظر همه چیز بمانید. این تجربه کاربری آب‌رسانی سنتی بود. یک صفحه می‌توانست آماده به نظر برسد، اما هر تلاشی برای تعامل با آن به هیچ نتیجه‌ای نمی‌رسید و منجر به سردرگمی کاربر و «کلیک‌های خشمگینانه» می‌شد.

ورود React 18: یک تغییر پارادایم با رندرینگ همزمان

نوآوری اصلی React 18، همزمانی (concurrency) است. این به React اجازه می‌دهد تا چندین به‌روزرسانی وضعیت را به طور همزمان آماده کند و کارهای رندرینگ را بدون مسدود کردن رشته اصلی متوقف، از سر بگیرد یا رها کند. در حالی که این موضوع پیامدهای عمیقی برای رندرینگ سمت کلاینت دارد، اما کلیدی است که یک معماری رندرینگ سرور بسیار هوشمندتر را باز می‌کند.

همزمانی دو ویژگی حیاتی را فعال می‌کند که به طور هماهنگ برای ممکن ساختن آب‌رسانی انتخابی کار می‌کنند:

  1. رندرینگ جریانی SSR: سرور می‌تواند HTML را به صورت تکه‌تکه (chunks) همزمان با رندر شدن ارسال کند، به جای اینکه منتظر آماده شدن کل صفحه بماند.
  2. آب‌رسانی انتخابی: React می‌تواند آب‌رسانی صفحه را قبل از رسیدن کامل جریان HTML و تمام جاوا اسکریپت شروع کند، و می‌تواند این کار را به شیوه‌ای غیرمسدودکننده و اولویت‌بندی شده انجام دهد.

مفهوم اصلی: آب‌رسانی انتخابی چیست؟

آب‌رسانی انتخابی مدل «همه یا هیچ» را از بین می‌برد. به جای یک کار واحد و یکپارچه، آب‌رسانی به مجموعه‌ای از کارهای کوچک‌تر، قابل مدیریت و قابل اولویت‌بندی تبدیل می‌شود. این به React اجازه می‌دهد تا کامپوننت‌ها را به محض در دسترس قرار گرفتن آب‌رسانی کند و مهم‌تر از همه، کامپوننت‌هایی را که کاربر فعالانه در تلاش برای تعامل با آن‌هاست، در اولویت قرار دهد.

عناصر کلیدی: رندرینگ جریانی SSR و ``

برای درک آب‌رسانی انتخابی، ابتدا باید دو ستون اصلی آن را درک کنید: رندرینگ جریانی SSR و کامپوننت ``.

رندرینگ جریانی SSR

با رندرینگ جریانی SSR، سرور مجبور نیست برای تکمیل واکشی‌های کند داده (مانند یک فراخوانی API برای بخش نظرات) منتظر بماند تا HTML اولیه را ارسال کند. در عوض، می‌تواند فوراً HTML بخش‌هایی از صفحه را که آماده هستند، مانند طرح اصلی و محتوا، ارسال کند. برای بخش‌های کندتر، یک جایگزین (placeholder) (یک UI جایگزین یا fallback) ارسال می‌کند. هنگامی که داده‌ها برای بخش کند آماده شد، سرور HTML اضافی و یک اسکریپت درون‌خطی را برای جایگزینی placeholder با محتوای واقعی به صورت جریانی ارسال می‌کند. این بدان معناست که کاربر ساختار صفحه و محتوای اصلی را بسیار سریع‌تر می‌بیند.

مرز ``

کامپوننت `` مکانیزمی است که شما با استفاده از آن به React می‌گویید کدام بخش‌های برنامه شما می‌توانند به صورت ناهمزمان و بدون مسدود کردن بقیه صفحه بارگذاری شوند. شما یک کامپوننت کند را در `` قرار می‌دهید و یک پراپ `fallback` ارائه می‌دهید، که همان چیزی است که React هنگام بارگذاری کامپوننت رندر می‌کند.

در سرور، `` سیگنالی برای استریمینگ است. هنگامی که سرور با یک مرز `` مواجه می‌شود، می‌داند که می‌تواند ابتدا HTML جایگزین (fallback) را ارسال کند و بعداً وقتی HTML کامپوننت واقعی آماده شد، آن را استریم کند. در مرورگر، مرزهای `` «جزایری» را تعریف می‌کنند که می‌توانند به طور مستقل آب‌رسانی شوند.

در اینجا یک مثال مفهومی آورده شده است:


function App() {
  return (
    <div>
      <Header />
      <main>
        <ArticleContent />
        <Suspense fallback={<CommentsSkeleton />}>
          <CommentsSection />  <!-- This component might fetch data -->
        </Suspense>
      </main>
      <Suspense fallback={<ChatWidgetLoader />}>
        <ChatWidget /> <!-- This is a heavy third-party script -->
      </Suspense>
      <Footer />
    </div>
  );
}

در این مثال، `Header`، `ArticleContent` و `Footer` بلافاصله رندر و استریم می‌شوند. مرورگر HTML مربوط به `CommentsSkeleton` و `ChatWidgetLoader` را دریافت خواهد کرد. بعداً، هنگامی که `CommentsSection` و `ChatWidget` در سرور آماده شوند، HTML آن‌ها به کلاینت استریم می‌شود. این مرزهای `` درزهایی را ایجاد می‌کنند که به آب‌رسانی انتخابی اجازه می‌دهند جادوی خود را به کار گیرد.

چگونه کار می‌کند: بارگذاری مبتنی بر اولویت در عمل

نبوغ واقعی آب‌رسانی انتخابی در نحوه استفاده از تعامل کاربر برای تعیین ترتیب عملیات نهفته است. React دیگر از یک اسکریپت آب‌رسانی سفت و سخت و از بالا به پایین پیروی نمی‌کند؛ بلکه به صورت پویا به کاربر پاسخ می‌دهد.

کاربر در اولویت است

این اصل اصلی است: React آب‌رسانی کامپوننت‌هایی را که کاربر با آنها تعامل می‌کند، در اولویت قرار می‌دهد.

در حالی که React در حال آب‌رسانی صفحه است، شنوندگان رویداد را در سطح ریشه متصل می‌کند. اگر کاربر روی دکمه‌ای در داخل کامپوننتی که هنوز آب‌رسانی نشده کلیک کند، React کار بسیار هوشمندانه‌ای انجام می‌دهد:

  1. ضبط رویداد: React رویداد کلیک را در ریشه ضبط می‌کند.
  2. اولویت‌بندی: مشخص می‌کند که کاربر روی کدام کامپوننت کلیک کرده است. سپس اولویت آب‌رسانی آن کامپوننت خاص و کامپوننت‌های والد آن را بالا می‌برد. هر کار آب‌رسانی با اولویت پایین که در حال انجام است، متوقف می‌شود.
  3. آب‌رسانی و بازپخش: React به سرعت کامپوننت هدف را آب‌رسانی می‌کند. پس از تکمیل آب‌رسانی و اتصال کنترل‌کننده `onClick`، React رویداد کلیک ضبط شده را بازپخش می‌کند.

از دیدگاه کاربر، تعامل به سادگی کار می‌کند، گویی که کامپوننت از همان ابتدا تعاملی بوده است. آنها کاملاً بی‌اطلاع هستند که یک رقص اولویت‌بندی پیچیده در پشت صحنه اتفاق افتاده تا این کار فوراً انجام شود.

یک سناریوی گام به گام

بیایید مثال صفحه فروشگاه الکترونیکی خود را مرور کنیم تا این موضوع را در عمل ببینیم. این صفحه دارای یک گرید اصلی محصولات، یک نوار کناری با فیلترهای پیچیده، و یک ویجت چت سنگین شخص ثالث در پایین صفحه است.

  1. استریمینگ از سرور: سرور پوسته اولیه HTML، شامل گرید محصولات را ارسال می‌کند. نوار کناری و ویجت چت در `` پیچیده شده‌اند و UIهای جایگزین آنها (اسکلت‌ها/لودرها) ارسال می‌شوند.
  2. رندر اولیه: مرورگر گرید محصولات را رندر می‌کند. کاربر می‌تواند محصولات را تقریباً بلافاصله ببیند. TTI هنوز بالاست زیرا هیچ جاوا اسکریپتی هنوز متصل نشده است.
  3. بارگذاری کد: باندل‌های جاوا اسکریپت شروع به دانلود می‌کنند. فرض کنید کد مربوط به نوار کناری و ویجت چت در تکه‌های جداگانه و تقسیم‌شده کد قرار دارند.
  4. تعامل کاربر: قبل از اینکه هر چیزی آب‌رسانی شود، کاربر محصولی را که دوست دارد می‌بیند و روی دکمه «افزودن به سبد خرید» در داخل گرید محصولات کلیک می‌کند.
  5. جادوی اولویت‌بندی: React کلیک را ضبط می‌کند. می‌بیند که کلیک در داخل کامپوننت `ProductGrid` اتفاق افتاده است. فوراً آب‌رسانی بخش‌های دیگر صفحه را (که ممکن است تازه شروع کرده باشد) متوقف یا معلق می‌کند و منحصراً بر روی آب‌رسانی `ProductGrid` تمرکز می‌کند.
  6. تعامل سریع: کامپوننت `ProductGrid` خیلی سریع آب‌رسانی می‌شود زیرا کد آن احتمالاً در باندل اصلی قرار دارد. کنترل‌کننده `onClick` متصل شده و رویداد کلیک ضبط شده بازپخش می‌شود. کالا به سبد خرید اضافه می‌شود. کاربر بازخورد فوری دریافت می‌کند.
  7. از سرگیری آب‌رسانی: اکنون که تعامل با اولویت بالا انجام شده است، React کار خود را از سر می‌گیرد. به آب‌رسانی نوار کناری ادامه می‌دهد. در نهایت، وقتی کد ویجت چت می‌رسد، آن کامپوننت را در آخر آب‌رسانی می‌کند.

نتیجه؟ TTI برای مهم‌ترین بخش صفحه تقریباً آنی بود، که توسط قصد خود کاربر هدایت می‌شد. TTI کلی صفحه دیگر یک عدد واحد و ترسناک نیست، بلکه یک فرآیند تدریجی و کاربر-محور است.

مزایای ملموس برای مخاطبان جهانی

تأثیر آب‌رسانی انتخابی عمیق است، به ویژه برای برنامه‌هایی که به مخاطبان متنوع و جهانی با شرایط شبکه و قابلیت‌های دستگاهی مختلف خدمات ارائه می‌دهند.

بهبود چشمگیر عملکرد درک‌شده

بزرگترین مزیت، بهبود عظیم در عملکرد درک‌شده توسط کاربر است. با در دسترس قرار دادن بخش‌هایی از صفحه که کاربر با آنها تعامل می‌کند، برنامه *احساس* سریع‌تری دارد. این برای حفظ کاربر حیاتی است. برای کاربری با شبکه کند 3G در یک کشور در حال توسعه، تفاوت بین انتظار ۱۵ ثانیه‌ای برای تعاملی شدن کل صفحه و توانایی تعامل با محتوای اصلی در ۳ ثانیه، بسیار زیاد است.

Core Web Vitals بهتر

آب‌رسانی انتخابی مستقیماً بر Core Web Vitals گوگل تأثیر می‌گذارد:

جداسازی محتوا از کامپوننت‌های سنگین

برنامه‌های وب مدرن اغلب با اسکریپت‌های سنگین شخص ثالث برای تحلیل، تست A/B، چت‌های پشتیبانی مشتری یا تبلیغات بارگذاری می‌شوند. در گذشته، این اسکریپت‌ها می‌توانستند کل برنامه را از تعاملی شدن باز دارند. با آب‌رسانی انتخابی و ``، این کامپوننت‌های غیرحیاتی می‌توانند کاملاً جدا شوند. محتوای اصلی برنامه می‌تواند بارگذاری و تعاملی شود در حالی که این اسکریپت‌های سنگین در پس‌زمینه بارگذاری و آب‌رسانی می‌شوند، بدون اینکه بر تجربه اصلی کاربر تأثیر بگذارند.

برنامه‌های انعطاف‌پذیرتر

از آنجا که آب‌رسانی می‌تواند به صورت تکه‌ای انجام شود، یک خطا در یک کامپوننت غیراساسی (مانند ویجت رسانه‌های اجتماعی) لزوماً کل صفحه را خراب نخواهد کرد. React به طور بالقوه می‌تواند خطا را در داخل آن مرز `` جدا کند در حالی که بقیه برنامه تعاملی باقی می‌ماند.

پیاده‌سازی عملی و بهترین شیوه‌ها

پذیرش آب‌رسانی انتخابی بیشتر به ساختاردهی صحیح برنامه شما مربوط می‌شود تا نوشتن کدهای پیچیده جدید. فریم‌ورک‌های مدرن مانند Next.js (با App Router خود) و Remix بسیاری از تنظیمات سرور را برای شما انجام می‌دههند، اما درک اصول اصلی کلیدی است.

پذیرش API `hydrateRoot`

در سمت کلاینت، نقطه ورود برای این رفتار جدید، API `hydrateRoot` است. شما از `ReactDOM.hydrate` قدیمی به `ReactDOM.hydrateRoot` تغییر خواهید داد.


// Before (Legacy)
import { hydrate } from 'react-dom';
const container = document.getElementById('root');
hydrate(<App />, container);

// After (React 18+)
import { hydrateRoot } from 'react-dom/client';
const container = document.getElementById('root');
const root = hydrateRoot(container, <App />);

این تغییر ساده برنامه شما را به ویژگی‌های رندرینگ همزمان جدید، از جمله آب‌رسانی انتخابی، مجهز می‌کند.

استفاده استراتژیک از ``

قدرت آب‌رسانی انتخابی با نحوه قرار دادن مرزهای `` شما باز می‌شود. هر کامپوننت کوچکی را نپوشانید؛ به واحدهای منطقی UI یا «جزایری» فکر کنید که می‌توانند به طور مستقل و بدون ایجاد اختلال در جریان کاربر بارگذاری شوند.

نامزدهای خوب برای مرزهای `` عبارتند از:

ترکیب با `React.lazy` برای تقسیم کد

آب‌رسانی انتخابی هنگامی که با تقسیم کد از طریق `React.lazy` ترکیب شود، حتی قدرتمندتر می‌شود. این تضمین می‌کند که جاوا اسکریپت برای کامپوننت‌های با اولویت پایین شما حتی تا زمانی که به آن نیاز نباشد دانلود نمی‌شود و این امر اندازه باندل اولیه را بیشتر کاهش می‌دهد.


import React, { Suspense, lazy } from 'react';

const CommentsSection = lazy(() => import('./CommentsSection'));
const ChatWidget = lazy(() => import('./ChatWidget'));

function App() {
  return (
    <div>
      <ArticleContent />
      <Suspense fallback={<CommentsSkeleton />}>
        <CommentsSection />
      </Suspense>
      <Suspense fallback={null}> <!-- No visual loader needed for a hidden widget -->
        <ChatWidget />
      </Suspense>
    </div>
  );
}

در این ساختار، کد جاوا اسکریپت برای `CommentsSection` و `ChatWidget` در فایل‌های جداگانه‌ای قرار خواهد گرفت. مرورگر فقط زمانی آن‌ها را واکشی می‌کند که React تصمیم به رندر کردنشان بگیرد، و آنها به طور مستقل و بدون مسدود کردن `ArticleContent` اصلی آب‌رسانی خواهند شد.

تنظیمات سمت سرور با `renderToPipeableStream`

برای کسانی که در حال ساخت یک راه‌حل SSR سفارشی هستند، API سمت سرور برای استفاده `renderToPipeableStream` است. این API به طور خاص برای استریمینگ طراحی شده و به طور یکپارچه با `` ادغام می‌شود. این به شما کنترل دقیقی بر زمان ارسال HTML و نحوه مدیریت خطاها می‌دهد. با این حال، برای اکثر توسعه‌دهندگان، یک متا-فریم‌ورک مانند Next.js مسیر توصیه‌شده است زیرا این پیچیدگی را پنهان می‌کند.

آینده: کامپوننت‌های سرور React

آب‌رسانی انتخابی یک گام بزرگ رو به جلو است، اما بخشی از یک داستان حتی بزرگ‌تر است. تکامل بعدی، کامپوننت‌های سرور React (RSCs) هستند. RSCها کامپوننت‌هایی هستند که منحصراً در سرور اجرا می‌شوند و هرگز جاوا اسکریپت خود را به کلاینت ارسال نمی‌کنند. این بدان معناست که آنها اصلاً نیازی به آب‌رسانی ندارند و باندل جاوا اسکریپت سمت کلاینت را حتی بیشتر کاهش می‌دهند.

آب‌رسانی انتخابی و RSCها کاملاً با هم کار می‌کنند. بخش‌هایی از برنامه شما که صرفاً برای نمایش داده‌ها هستند می‌توانند RSC باشند (جاوا اسکریپت صفر در سمت کلاینت)، در حالی که بخش‌های تعاملی می‌توانند کامپوننت‌های کلاینت باشند که از آب‌رسانی انتخابی بهره‌مند می‌شوند. این ترکیب، آینده ساخت برنامه‌های بسیار کارآمد و تعاملی با React را نشان می‌دهد.

نتیجه‌گیری: آب‌رسانی هوشمندانه‌تر، نه سخت‌تر

آب‌رسانی انتخابی React چیزی بیش از یک بهینه‌سازی عملکرد است؛ این یک تغییر بنیادین به سمت یک معماری کاربر-محورتر است. با رهایی از محدودیت‌های «همه یا هیچ» گذشته، React 18 به توسعه‌دهندگان این قدرت را می‌دهد که برنامه‌هایی بسازند که نه تنها در بارگذاری سریع هستند، بلکه در تعامل نیز سریع عمل می‌کنند، حتی در شرایط شبکه چالش‌برانگیز.

نکات کلیدی واضح هستند:

به عنوان توسعه‌دهندگانی که برای مخاطبان جهانی می‌سازیم، هدف ما ایجاد تجربیاتی است که برای همه قابل دسترس، انعطاف‌پذیر و لذت‌بخش باشد. با پذیرش قدرت آب‌رسانی انتخابی، می‌توانیم از منتظر گذاشتن کاربران خود دست برداریم و شروع به تحقق آن وعده کنیم، هر بار یک کامپوننت اولویت‌بندی شده.