تحميل البيانات بالتوازي: صفحة التدوينة المفردة (Loading Data in Parallel: Single Blog Post Page)
الدرس 22 من 34 · دورة TanStack Router الكاملة · 3 دقيقة و59 ثانية
الفيديو الأصلي باللغة الإنجليزية. إذا تعذّر تشغيله هنا، شاهده على موقع المؤلف. التفريغ النصي العربي الكامل أدناه.
مستودع الكود لهذا الدرس
الفرع:
loaders-3
[00:00] تعمل بشكلٍ سليم. إذًا في هذا المسار احتجنا إلى إرسال طلبٍ واحد فقط لجلب تدويناتنا. لكن في كثير من الحالات، قد تضطرّ إلى إرسال طلباتٍ متعدّدة هنا، وتحتاج أيضًا إلى التأكّد من أنّك تفعل ذلك بكفاءةٍ قدر الإمكان.
[00:14] إذًا فلنقل في إحدى تدويناتنا — أي فلنذهب إلى posts ربّما، أي posts/1 أو نحو ذلك. وفي هنا فلنقل نحتاج إلى تحميل البيانات الخاصّة بهذه التدوينة. وبالطبع، وكما نعرف، لدينا الدوالّ اللازمة لفعل ذلك؛ لدينا getPosts أو getPost
[00:31] حيث نمرّر لها المعرّف فنحصل على التدوينة، وكذلك getPostComments حيث نحصل على تعليقات تدوينةٍ مُعيّنة. إذًا الآن فلنقل نحتاج إلى إرسال هذين الطلبين في دالّة التحميل (loader function) الخاصّة بهذا المسار. فإذًا يقع هذا المسار هنا في posts
[00:46] $postId.tsx. فلنفتح ذلك إذًا، وفي هنا فلنمرّر دالّة التحميل لدينا ولنحمّل بياناتنا. وسَتَكُون بالطبع دالّةً غير متزامنة (async). فلنقل مثلًا أنّنا سننشئ ثابتًا (constant) اسمه post، ثم سَنتظر getPost عبر await ونمرّر له المعرّف.
[01:05] سَيَكُون المعرّف موجودًا في معامِلات URL لدينا، والتي نملك الوصول إليها من هنا.
[01:09] إذًا params، وفي هنا يمكننا ببساطة تمرير params id — أو — عذرًا — post id، وهو سَيَكُون من النوع string. وبالطبع في هذه الدالّة نتوقّع عددًا (number)، فيمكننا تحويله إلى عدد كما ترى هكذا. ويمكننا فعل الأمر نفسه
[01:22] لأجل التعليقات، وأن نستدعِ getPostComments هكذا.
[01:31] وما يمكننا فعله أنّنا نستطيع إرجاع التدوينة والتعليقات الخاصّة بها ببساطة. فإذا ألقينا نظرة إلى الشبكة (network) لدينا هنا، فسَنتبيّن — فلنحدّث الصفحة ربّما — أنّ طلباتنا تُرسَل.
[01:48] لكن هذا الطلب سَيُرسَل أولًا، ثم بعد اكتماله سَيُرسَل هذا الآخر بعده. وهذا بالطبع ليس فعّالًا كثيرًا، إذ إنّ هذين الطلبَين لا يعتمد أحدهما على
[02:01] الآخر. فإذًا لا نحتاج إلى انتظار انتهاء هذا كي نشغّل هذا الطلب الآخر، ويمكننا تشغيلهما بالتوازي (parallel) باستخدام promise.all. فلنقل مثلًا أنّنا ننسخ هذا، أي getPostComments.
[02:14] فلنزِل هذا. والآن فلنضِف مصفوفةً هنا سنحصل عليها من التدوينة والتعليقات، وفيهنا بدلًا من ذلك سَنتظر عبر await — promise.all.
[02:25] وبالطبع، وكما قد تعرف، في promise.all يمكننا تمرير مصفوفةٍ من الوعود (promises) ستعمل بالتوازي. فنحتاج إلى وضع عنصر التعليقات لدينا هنا، ولننسخ هذا ونضع عنصر التدوينة. فسَيَبدو الأمر
[02:39] هكذا. والآن سَنمتلك الشيء نفسه؛ لكن إذا حدّثنا الصفحة، فكما ترى، سَيُرسَل كلا الطلبَين بالتوازي.
[02:49] والآن مَلَكنا بياناتنا، فيمكننا أن نضيف بعض الترميز (markup). تذكّر أنّه في هذا المكوّن كانت لَدينا التدوينة في مكوّنٍ مختلف.
[02:58] ونحصل على الخطّافات (hooks) الخاصّة به باستخدام getRouteApi. فإذًا في هنا يمكننا الحصول على useLoaderData، ومن هذا الخطّاف سأحصل على تعليقاتي وتدوينتي. فإذًا — هنا useLoaderData — ثم فلنحصل على التدوينة والتعليقات. سألصق
[03:17] بعض الترميز هنا. الأمر بسيطٌ في غاية البساطة.
[03:22] فلنحفظ. وأنا هنا أعرض عنوان تدوينتي فقط، ومتن التدوينة (body)، ومحتويات التدوينة. وفي هذا div لدينا التعليقات؛ وكلّ تعليق وضعتُه في هذا li بهذه الخلفية البنفسجية.
[03:35] ولديّ أيضًا متن التعليق واسم المستخدم (username) لكاتِب التعليق.
[03:40] لدينا خطأ في TypeScript هنا، لأنّني عندما عرّفتُ نوع التعليقات نسيتُ أن أضيف نوع المستخدم (user) الذي تعود به الواجهة البرمجيّة (API).
[03:51] فإذًا لدينا معرّف المستخدم واسم المستخدم.
[03:55] إذًا الآن، كما ترى، لدينا تدوينتنا هنا مع تعليقاتها.