العربية

حقق أداء ويب أسرع مع الترطيب الانتقائي في React 18. يستكشف هذا الدليل الشامل التحميل القائم على الأولوية، والتصيير المتدفق من جانب الخادم، والتطبيق العملي لجمهور عالمي.

الترطيب الانتقائي في React: نظرة عميقة على تحميل المكونات القائم على الأولوية

في السعي الدؤوب لتحقيق أداء ويب متفوق، يتنقل مطورو الواجهة الأمامية باستمرار عبر مقايضة معقدة. نريد تطبيقات غنية وتفاعلية، لكننا نحتاجها أيضًا للتحميل الفوري والاستجابة دون تأخير، بغض النظر عن جهاز المستخدم أو سرعة الشبكة. لسنوات، كان التصيير من جانب الخادم (SSR) حجر الزاوية في هذا الجهد، حيث يوفر تحميلًا أوليًا سريعًا للصفحات وفوائد قوية لتحسين محركات البحث (SEO). ومع ذلك، جاء SSR التقليدي مع عنق زجاجة كبير: مشكلة الترطيب المزعجة "الكل أو لا شيء".

قبل أن تصبح الصفحة المنشأة بواسطة SSR تفاعلية حقًا، كان يجب تنزيل حزمة JavaScript الكاملة للتطبيق وتحليلها وتنفيذها. غالبًا ما أدى هذا إلى تجربة مستخدم محبطة حيث تبدو الصفحة كاملة وجاهزة ولكنها لا تستجيب للنقرات أو الإدخال، وهي ظاهرة تؤثر سلبًا على المقاييس الرئيسية مثل زمن التفاعل (TTI) والمقياس الأحدث التفاعل حتى التلوين التالي (INP).

وهنا يأتي دور React 18. بفضل محرك التصيير المتزامن الرائد، قدم React حلاً أنيقًا وقويًا في آن واحد: الترطيب الانتقائي (Selective Hydration). هذا ليس مجرد تحسين تدريجي؛ إنه تحول نموذجي أساسي في كيفية ظهور تطبيقات React في المتصفح. إنه يتجاوز نموذج الترطيب المتجانس إلى نظام حبيبي قائم على الأولوية يضع تفاعل المستخدم أولاً.

سيستكشف هذا الدليل الشامل آليات وفوائد وتطبيقات الترطيب الانتقائي في React. سنقوم بتفكيك كيفية عمله، ولماذا يغير قواعد اللعبة للتطبيقات العالمية، وكيف يمكنك الاستفادة منه لبناء تجارب مستخدم أسرع وأكثر مرونة.

فهم الماضي: تحدي الترطيب التقليدي في SSR

لتقدير ابتكار الترطيب الانتقائي تمامًا، يجب أن نفهم أولاً القيود التي صُمم للتغلب عليها. دعنا نعود إلى عالم التصيير من جانب الخادم قبل React 18.

ما هو التصيير من جانب الخادم (SSR)؟

في تطبيق React نموذجي يتم تصييره من جانب العميل (CSR)، يتلقى المتصفح ملف HTML صغيرًا وحزمة JavaScript كبيرة. يقوم المتصفح بعد ذلك بتنفيذ JavaScript لتصيير محتوى الصفحة. يمكن أن تكون هذه العملية بطيئة، مما يترك المستخدمين يحدقون في شاشة فارغة ويجعل من الصعب على زواحف محركات البحث فهرسة المحتوى.

يقلب SSR هذا النموذج. يقوم الخادم بتشغيل تطبيق React، وإنشاء HTML الكامل للصفحة المطلوبة، وإرساله إلى المتصفح. الفوائد فورية:

عنق الزجاجة في الترطيب "الكل أو لا شيء"

بينما يوفر HTML الأولي من SSR معاينة سريعة غير تفاعلية، فإن الصفحة ليست قابلة للاستخدام حقًا بعد. معالجات الأحداث (مثل `onClick`) وإدارة الحالة المحددة في مكونات React مفقودة. تسمى عملية إرفاق منطق JavaScript هذا بـ HTML الذي تم إنشاؤه بواسطة الخادم الترطيب (hydration).

وهنا تكمن المشكلة الكلاسيكية: كان الترطيب التقليدي عملية متجانسة ومتزامنة ومعيقة. لقد اتبع تسلسلاً صارمًا لا يرحم:

  1. يجب تنزيل حزمة JavaScript الكاملة للصفحة بأكملها.
  2. يجب على React تحليل وتنفيذ الحزمة بأكملها.
  3. ثم يتجول React في شجرة المكونات بأكملها من الجذر، ويرفق مستمعي الأحداث ويهيئ الحالة لكل مكون على حدة.
  4. فقط بعد اكتمال هذه العملية برمتها تصبح الصفحة تفاعلية.

تخيل أنك تتلقى سيارة جديدة مجمعة بالكامل وجميلة، ولكن يُقال لك إنه لا يمكنك فتح باب واحد، أو تشغيل المحرك، أو حتى إطلاق البوق حتى يتم تشغيل مفتاح رئيسي واحد لجميع إلكترونيات السيارة. حتى لو كنت تريد فقط إخراج حقيبتك من مقعد الراكب، يجب عليك انتظار كل شيء. كانت هذه هي تجربة المستخدم للترطيب التقليدي. يمكن أن تبدو الصفحة جاهزة، لكن أي محاولة للتفاعل معها لن تسفر عن أي شيء، مما يؤدي إلى ارتباك المستخدم و"نقرات الغضب".

دخول React 18: تحول نموذجي مع التصيير المتزامن

الابتكار الأساسي في React 18 هو التزامن (concurrency). يسمح هذا لـ React بإعداد تحديثات حالة متعددة في وقت واحد وإيقاف عمل التصيير مؤقتًا أو استئنافه أو التخلي عنه دون إعاقة الخيط الرئيسي (main thread). في حين أن لهذا آثارًا عميقة على التصيير من جانب العميل، إلا أنه المفتاح الذي يفتح بنية تصيير خادم أكثر ذكاءً.

يمكّن التزامن ميزتين حاسمتين تعملان جنبًا إلى جنب لجعل الترطيب الانتقائي ممكنًا:

  1. التصيير المتدفق من جانب الخادم (Streaming SSR): يمكن للخادم إرسال HTML في أجزاء (chunks) أثناء تصييرها، بدلاً من انتظار تجهيز الصفحة بأكملها.
  2. الترطيب الانتقائي (Selective Hydration): يمكن لـ React بدء ترطيب الصفحة قبل وصول دفق HTML الكامل وجميع ملفات JavaScript، ويمكنه القيام بذلك بطريقة غير معيقة وذات أولوية.

المفهوم الأساسي: ما هو الترطيب الانتقائي؟

يفكك الترطيب الانتقائي نموذج "الكل أو لا شيء". بدلاً من مهمة واحدة متجانسة، يصبح الترطيب سلسلة من المهام الأصغر والقابلة للإدارة والتحديد حسب الأولوية. يسمح لـ React بترطيب المكونات فور توفرها، والأهم من ذلك، إعطاء الأولوية للمكونات التي يحاول المستخدم التفاعل معها بنشاط.

المكونات الرئيسية: التصيير المتدفق من جانب الخادم و ``

لفهم الترطيب الانتقائي، يجب أولاً أن تستوعب ركيزتيه الأساسيتين: التصيير المتدفق من جانب الخادم ومكون ``.

التصيير المتدفق من جانب الخادم (Streaming SSR)

مع التصيير المتدفق من جانب الخادم، لا يتعين على الخادم انتظار عمليات جلب البيانات البطيئة (مثل استدعاء API لقسم التعليقات) حتى تكتمل قبل إرسال HTML الأولي. بدلاً من ذلك، يمكنه إرسال HTML على الفور لأجزاء الصفحة الجاهزة، مثل التخطيط الرئيسي والمحتوى. بالنسبة للأجزاء الأبطأ، يرسل عنصرًا نائبًا (واجهة مستخدم احتياطية). عندما تكون بيانات الجزء البطيء جاهزة، يقوم الخادم ببث HTML إضافي وسكربت مضمّن لاستبدال العنصر النائب بالمحتوى الفعلي. هذا يعني أن المستخدم يرى هيكل الصفحة والمحتوى الأساسي بشكل أسرع.

حدود ``

مكون `` هو الآلية التي تستخدمها لإخبار React بأي أجزاء من تطبيقك يمكن تحميلها بشكل غير متزامن دون إعاقة بقية الصفحة. تقوم بتغليف مكون بطيء في `` وتوفر خاصية `fallback`، وهي ما سيقوم React بتصييره أثناء تحميل المكون.

على الخادم، `` هو إشارة للتدفق. عندما يواجه الخادم حد ``، فإنه يعلم أنه يمكنه إرسال HTML الاحتياطي أولاً وبث HTML للمكون الفعلي لاحقًا عندما يكون جاهزًا. في المتصفح، تحدد حدود `` "الجزر" التي يمكن ترطيبها بشكل مستقل.

إليك مثال مفاهيمي:


function App() {
  return (
    <div>
      <Header />
      <main>
        <ArticleContent />
        <Suspense fallback={<CommentsSkeleton />}>
          <CommentsSection />  <!-- قد يجلب هذا المكون البيانات -->
        </Suspense>
      </main>
      <Suspense fallback={<ChatWidgetLoader />}>
        <ChatWidget /> <!-- هذا سكربت ثقيل من طرف ثالث -->
      </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 الأولي، بما في ذلك شبكة المنتجات. يتم تغليف الشريط الجانبي وودجت الدردشة في `` ويتم إرسال واجهات المستخدم الاحتياطية (الهياكل العظمية/المحملات).
  2. التصيير الأولي: يقوم المتصفح بتصيير شبكة المنتجات. يمكن للمستخدم رؤية المنتجات على الفور تقريبًا. لا يزال زمن التفاعل (TTI) مرتفعًا لأنه لم يتم إرفاق أي JavaScript بعد.
  3. تحميل الكود: تبدأ حزم JavaScript في التنزيل. لنفترض أن كود الشريط الجانبي وودجت الدردشة موجود في أجزاء منفصلة ومقسمة (code-split).
  4. تفاعل المستخدم: قبل الانتهاء من ترطيب أي شيء، يرى المستخدم منتجًا يعجبه وينقر على زر "إضافة إلى السلة" داخل شبكة المنتجات.
  5. سحر تحديد الأولويات: يلتقط React النقرة. يرى أن النقرة حدثت داخل مكون `ProductGrid`. يقوم على الفور بإلغاء أو إيقاف ترطيب أجزاء أخرى من الصفحة (والتي ربما يكون قد بدأها للتو) ويركز حصريًا على ترطيب `ProductGrid`.
  6. تفاعلية سريعة: يتم ترطيب مكون `ProductGrid` بسرعة كبيرة لأن الكود الخاص به من المحتمل أن يكون في الحزمة الرئيسية. يتم إرفاق معالج `onClick`، ويتم إعادة تشغيل حدث النقر الذي تم التقاطه. تتم إضافة العنصر إلى السلة. يحصل المستخدم على ردود فعل فورية.
  7. استئناف الترطيب: الآن بعد أن تم التعامل مع التفاعل عالي الأولوية، يستأنف React عمله. يبدأ في ترطيب الشريط الجانبي. أخيرًا، عندما يصل كود ودجت الدردشة، يقوم بترطيب هذا المكون أخيرًا.

النتيجة؟ كان زمن التفاعل (TTI) للجزء الأكثر أهمية من الصفحة شبه فوري، مدفوعًا بنية المستخدم نفسه. لم يعد TTI للصفحة بأكملها رقمًا واحدًا مخيفًا بل عملية تقدمية تتمحور حول المستخدم.

الفوائد الملموسة للجمهور العالمي

تأثير الترطيب الانتقائي عميق، خاصة للتطبيقات التي تخدم جمهورًا عالميًا متنوعًا بظروف شبكة وقدرات أجهزة متفاوتة.

تحسين الأداء المتصور بشكل كبير

الفائدة الأكبر هي التحسن الهائل في الأداء الذي يدركه المستخدم. من خلال إتاحة أجزاء الصفحة التي يتفاعل معها المستخدم أولاً، يبدو التطبيق أسرع. هذا أمر حاسم للاحتفاظ بالمستخدمين. بالنسبة لمستخدم على شبكة 3G بطيئة في بلد نامٍ، فإن الفرق بين انتظار 15 ثانية لتصبح الصفحة بأكملها تفاعلية مقابل القدرة على التفاعل مع المحتوى الرئيسي في 3 ثوانٍ هو فرق هائل.

مؤشرات أداء الويب الأساسية أفضل

يؤثر الترطيب الانتقائي بشكل مباشر على مؤشرات أداء الويب الأساسية من Google:

فصل المحتوى عن المكونات الثقيلة

غالبًا ما تكون تطبيقات الويب الحديثة محملة بسكربتات ثقيلة من جهات خارجية للتحليلات، أو اختبار A/B، أو محادثات دعم العملاء، أو الإعلانات. تاريخياً، كان بإمكان هذه السكربتات منع التطبيق بأكمله من أن يصبح تفاعليًا. مع الترطيب الانتقائي و ``، يمكن عزل هذه المكونات غير الحرجة تمامًا. يمكن تحميل محتوى التطبيق الرئيسي ويصبح تفاعليًا بينما يتم تحميل هذه السكربتات الثقيلة وترطيبها في الخلفية، دون التأثير على تجربة المستخدم الأساسية.

تطبيقات أكثر مرونة

نظرًا لأن الترطيب يمكن أن يحدث في أجزاء، فإن خطأ في مكون واحد غير أساسي (مثل ودجت وسائل التواصل الاجتماعي) لن يكسر بالضرورة الصفحة بأكملها. يمكن لـ React عزل الخطأ داخل حد `` هذا بينما يظل باقي التطبيق تفاعليًا.

التنفيذ العملي وأفضل الممارسات

يعتمد تبني الترطيب الانتقائي على هيكلة تطبيقك بشكل صحيح أكثر من كتابة كود جديد معقد. تتولى أطر العمل الحديثة مثل Next.js (مع App Router) و Remix الكثير من إعدادات الخادم نيابة عنك، لكن فهم المبادئ الأساسية هو المفتاح.

اعتماد واجهة برمجة التطبيقات `hydrateRoot`

على جانب العميل، نقطة الدخول لهذا السلوك الجديد هي واجهة برمجة التطبيقات `hydrateRoot`. ستتحول من `ReactDOM.hydrate` القديمة إلى `ReactDOM.hydrateRoot`.


// قبل (القديم)
import { hydrate } from 'react-dom';
const container = document.getElementById('root');
hydrate(<App />, container);

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

يؤدي هذا التغيير البسيط إلى تمكين تطبيقك من الاستفادة من ميزات التصيير المتزامن الجديدة، بما في ذلك الترطيب الانتقائي.

الاستخدام الاستراتيجي لـ ``

يتم إطلاق العنان لقوة الترطيب الانتقائي من خلال كيفية وضع حدود `` الخاصة بك. لا تقم بتغليف كل مكون صغير؛ فكر من حيث الوحدات المنطقية لواجهة المستخدم أو "الجزر" التي يمكن تحميلها بشكل مستقل دون تعطيل تدفق المستخدم.

المرشحون الجيدون لحدود `` يشملون:

الجمع مع `React.lazy` لتقسيم الكود

يكون الترطيب الانتقائي أكثر قوة عند دمجه مع تقسيم الكود عبر `React.lazy`. هذا يضمن عدم تنزيل JavaScript لمكوناتك ذات الأولوية المنخفضة حتى تكون هناك حاجة إليها، مما يقلل من حجم الحزمة الأولية بشكل أكبر.


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}> <!-- لا حاجة لمؤشر تحميل مرئي لعنصر واجهة مستخدم مخفي -->
        <ChatWidget />
      </Suspense>
    </div>
  );
}

في هذا الإعداد، سيكون كود JavaScript لـ `CommentsSection` و `ChatWidget` في ملفات منفصلة. سيقوم المتصفح بجلبها فقط عندما يقرر React تصييرها، وسيتم ترطيبها بشكل مستقل دون إعاقة `ArticleContent` الرئيسي.

إعداد جانب الخادم مع `renderToPipeableStream`

بالنسبة لأولئك الذين يبنون حلاً مخصصًا لـ SSR، فإن واجهة برمجة التطبيقات من جانب الخادم التي يجب استخدامها هي `renderToPipeableStream`. تم تصميم هذه الواجهة خصيصًا للبث وتتكامل بسلاسة مع ``. تمنحك تحكمًا دقيقًا في وقت إرسال HTML وكيفية التعامل مع الأخطاء. ومع ذلك، بالنسبة لمعظم المطورين، يعد إطار عمل مثل Next.js هو المسار الموصى به لأنه يخفي هذا التعقيد.

المستقبل: مكونات خادم React

يعد الترطيب الانتقائي خطوة هائلة إلى الأمام، لكنه جزء من قصة أكبر. التطور التالي هو مكونات خادم React (RSCs). RSCs هي مكونات تعمل حصريًا على الخادم ولا ترسل أبدًا JavaScript الخاص بها إلى العميل. هذا يعني أنها لا تحتاج إلى الترطيب على الإطلاق، مما يقلل من حزمة JavaScript من جانب العميل بشكل أكبر.

يعمل الترطيب الانتقائي و RSCs معًا بشكل مثالي. يمكن أن تكون أجزاء تطبيقك المخصصة لعرض البيانات فقط RSCs (صفر JS من جانب العميل)، بينما يمكن أن تكون الأجزاء التفاعلية مكونات عميل تستفيد من الترطيب الانتقائي. يمثل هذا المزيج مستقبل بناء تطبيقات عالية الأداء وتفاعلية باستخدام React.

الخاتمة: الترطيب بذكاء، وليس بجهد أكبر

إن الترطيب الانتقائي في React هو أكثر من مجرد تحسين للأداء؛ إنه تحول أساسي نحو بنية أكثر تركيزًا على المستخدم. من خلال التحرر من قيود "الكل أو لا شيء" في الماضي، يمكّن React 18 المطورين من بناء تطبيقات ليست سريعة في التحميل فحسب، بل سريعة في التفاعل أيضًا، حتى في ظل ظروف الشبكة الصعبة.

النقاط الرئيسية واضحة:

كمطورين نبني لجمهور عالمي، هدفنا هو إنشاء تجارب سهلة الوصول ومرنة وممتعة للجميع. من خلال تبني قوة الترطيب الانتقائي، يمكننا التوقف عن جعل مستخدمينا ينتظرون والبدء في الوفاء بهذا الوعد، مكونًا ذا أولوية في كل مرة.

الترطيب الانتقائي في React: نظرة عميقة على تحميل المكونات القائم على الأولوية | MLOG