دورة TanStack Router الكاملة › دورة TanStack Router الكاملة 1 / 1 السابق التالي

دوالّ التحميل: صفحة المنشورات (Loader Functions: Posts Page)

الدرس 20 من 34 · دورة TanStack Router الكاملة · 7 دقيقة و11 ثانية

الفيديو الأصلي باللغة الإنجليزية. إذا تعذّر تشغيله هنا، شاهده على موقع المؤلف. التفريغ النصي العربي الكامل أدناه.

مستودع الكود لهذا الدرس

الفرع: loaders-1

[00:01] عندما يتعلّق الأمر بتحميل البيانات في TanStack Router، فنحن لا نحمّل البيانات فقط داخل مكوّن (component) مسارنا، ربّما في أثرٍ (effect) أو ما شابه ذلك. غير أنّ الطريقة التي نفعل بها ذلك هي أن نُعرِّف دالّة تحميل (load function) يمكننا تمريرها هنا إلى createFileRoute. ففي

[00:14] هنا يمكننا أن نمرّر دالّة تحميل — عذرًا — دالّة التحميل (loader function)، ويمكننا هنا القيام بأيّ جلبٍ للبيانات (data fetching) نحتاج إلى القيام به. هذا يضمن أنّ البيانات المطلوبة للمسار سَتُحمَّل في أقرب وقتٍ ممكن، ويمكن أيضًا أن تُحمَّل مسبقًا (preload)

[00:29] حتى قبل أن نزور المسار. سنتحدث لاحقًا بمزيدٍ من التفصيل عن التحميل المسبق (preloading). وكذلك افتراضيًّا (default) سَتُخزَّن أيّ بياناتٍ سنحمّلها هنا في الذاكرة المؤقتة (cache) أيضًا، ويمكننا التحكّم في سلوك هذه الذاكرة المؤقتة. وسنتناول

[00:43] التخزين المؤقت (caching) أيضًا في قسمٍ لاحق. وفي دالّة التحميل هذه سَنَتَلقّى أشياء مثل السياق (context). وسنحصل أيضًا على معاملات URL في params. وسنحصل أيضًا على المسار نفسه،

[00:56] معلوماتٍ عن المسار. غير أنّنا لن نحصل على معاملات البحث (search parameters). فإذا كتبت search هنا فلن نجد أيّ خاصيّة (property) خاصة بمعاملات البحث. وهذا لِسببٍ سَنناقشه أيضًا

[01:09] بعد قليل. ولدينا أيضًا، إضافةً إلى الـ loader، دالّة قبل التحميل (beforeLoad) يمكننا تمريرها هنا، وهذه يمكن أن تكون مفيدةً جدًّا في مواقف كثيرة. فلنقل مثلًا إن كنّا نحتاج، قبل تصيير (render) مسارنا،

[01:24] قبل تحميل أيّ بيانات، إلى إعادة التوجيه (redirect) إلى مسارٍ مختلف. فربّما لسنا مُصادَقين (authenticated) مثلًا، إذًا نحتاج إلى إعادة التوجيه. وتذكّر أيضًا، حين ناقشنا السياق، أنّنا ذكرنا أنّه إضافةً إلى وجود سياق الجذر (root context) الذي

[01:38] سَيَكُون متاحًا في كلّ مكان، يمكننا أيضًا أن يكون لَدَينا سياقٌ لمسارٍ بعينه، وسَيَكُون متاحًا لهذا المسار فقط ولأبنائه (children).

[01:48] ويمكن فعل ذلك باستخدام دالّة قبل التحميل هذه بإعادة (return) كائنٍ (object) هنا. فإذا أعدنا كائنًا فسَيَكُون هذا هو السياق لهذا المسار فقط ولأبنائه. وسنجرب ذلك أيضًا بعد قليل. لكن

[02:02] فلنحمّل، في الوقت الحالي، بعض البيانات من واجهة (API) الوهمية dummy JSON. فلدينا هنا واجهة DummyJSON الوهمية يمكننا مجرّد إرسال بعض الطلبات عبرها وتلقّي بعض البيانات الوهمية. فلنستخدمها إذًا لنحاول ربّما تحميل بعض البيانات في

[02:15] تطبيقنا.

[02:16] إذًا ما سأفعله هو أنّني سأُعرِّف بعض الدوالّ (functions) من أجل جلب بعض البيانات من هذه الواجهة الوهمية. سأضعها ربّما في مجلّد المصدر (source) لدينا، وسأنشئ ملفًّا (file) داخل مجلّد data.

[02:29] فلنسمّه posts أيضًا، لأنّنا سَنحمّل بعض المنشورات الوهمية (dummy posts) هنا.

[02:34] سألصق بعض الأشياء ثم فلنمرّ عليها سريعًا. فلديّ الأنواع (types) التي تُعِيدها هذه الواجهة. فالمنشور (post) سَيَتضمّن ID و title و body و userId وهكذا. وتُعيد أشياء أخرى أيضًا، لكن فلنُبسِط

[02:47] الأمر ونقل إنّنا نهتم فقط بهذه الخصائص (properties).

[02:52] وسَنحمّل أيضًا التعليقات (comments) الخاصة بالمنشور، وهذا هو النوع الخاصّ بها.

[02:57] وعندما نرسل طلبًا لجلب المنشورات سَنَتَلقّى المنشورات — وهي مصفوفة (array) من المنشورات — إضافةً إلى معلومات الترقيم (pagination). فلدينا total و skip و limit، وهي مثلها مثلها عند جلب التعليقات أيضًا. وهنا

[03:11] لديّ بضعة دوالّ — أو في الحقيقة ثلاث دوالّ. واحدة للحصول على منشور — عذرًا — للحصول على قائمة منشورات. ولدينا page هنا حيث يمكننا تحميل صفحات مختلفة. فنستدعي هذه الواجهة الوهمية ونضيف فقط limit و skip من أجل

[03:25] تحميل صفحات مختلفة بناءً على هذا المعامل page هنا. ثم نُعيد JSON لدينا إذا كانت الاستجابة (response) سليمة وإلّا نرمي خطأ (error)، ونفعل الشيء نفسه للدوالّ الأخرى أيضًا. فدالّة getPost تستخرج منشورًا بعينه من خلال

[03:39] استقبال المعرّف id، ونستدعي endpoint هذا ونمرّر له المعرّف ونعيد البيانات أو نرمي خطأ وهكذا، وهي مثلها عند التعليقات أيضًا. فسأحفظ هذا الملف الآن فلنحاول استخدام هذه الدوالّ في مسارنا. فتذكّر

[03:52] أنّه كان لَدَينا هذا المسار posts.index.tsx وهو /posts وهو الذي يُفترض أن يحتوي ربّما على قائمة منشورات. فلنحاول استدعاء دالّة getPosts من أجل تحميل بعض البيانات ثم استخدام

[04:05] هذه البيانات في مكوّننا. ولنجرب أيضًا أن نمرّر الدالة — دالّة getPosts هذه — بوصفها سياقًا لهذا المسار بإعادةٍ هنا. إذًا في beforeLoad يمكننا ببساطة أن نُعيد وفلنقل getPosts ثم فلنستورد

[04:25] دالّة getPosts لدينا.

[04:29] هذا سيضمن أنّ هذا السياق متاح لهذا المسار وهو /posts، وإن كان له أيّ أبناء (children). إذًا في دالّة التحميل لدينا يمكننا الحصول على سياقنا، ومن سياقنا سَنَجِد أنّه لَدَينا وصول

[04:43] إلى السياق الأب (parent context) لدينا: user و login و logout إضافةً إلى getPosts، وسَيَكون هذا مشابهًا أيضًا إن كان لمسار post أيّ أبناء كذلك، فهم سَيَكون لَدَيهم وصول إلى getPosts. ولذلك فالسياق يمكن أيضًا أن يكون مفيدًا لتمرير

[04:59] دوالّ ربّما سَتُستخدَم من قِبَل مساراتٍ متعدّدة. فربّما في مثالنا ليست مفيدة جدًّا، لكن كما تتخيّل يمكن أن تكون لِهذا حالاتُ استخدام (use cases)؛ لكن فلنحاول الآن، في دالّة التحميل لدينا الآن، أن نحصل من سياقنا على

[05:16] فلنفكِّك (destructure) دالّة getPosts ونستدعيها بإنشاء ثابتٍ (constant) نسمّيه posts ثم await getPosts. وبما أنّنا نستخدم await فلنجعل هذه دالّة async، لكن تذكّر أنّ هذه الدالّة سَتُعيد

[05:32] استجابة المنشورات (posts response) التي سَتَتضمّن المنشورات ومعلومات الترقيم. لكن فلنقل إنّنا نحتاج فقط إلى إعادة المنشورات. إذًا فلنُعِد هنا posts، أو في الواقع عذرًا، فلنُعِد كائنًا (object) يتضمّن منشوراتنا

[05:46] التي سَتَكُون في posts.posts.

[05:53] أعتقد أنّني ربّما — نعم — لديّ فاصلةٌ ناقصة هنا.

[05:56] إذًا بإعادة بعض البيانات من دالّة التحميل هذه سَتَكُون هذه البيانات متاحة في مكوّننا. وكيف يمكننا الوصول إليها؟ فهو باستخدام خطّاف (hook) أيضًا. فلنستخدم خطّافًا هنا داخل مسارنا، وهذا يُدعى useLoader

[06:12] Data. وبما أنّ لدينا أمان أنواع (type safety) لكلّ شيء، فبطبيعة الحال سنحصل هنا على الإكمال التلقائي (autocomplete) لمنشوراتنا.

[06:18] سَيَكون هذا من النوع الصحيح أيضًا. ويمكننا ببساطة المرور عبر منشوراتنا في حلقة (loop) وعرضها. سأضع بعض الشيفرة هنا، وهذا بديهي جدًّا. فلنقل ربّما هنا. فلنضع هذه الحلقة.

[06:32] فما نفعله هنا هو مجرّد حلقةٍ عبر منشوراتنا، ثم عرض رابطٍ (link) سَيَعْرض عنوان المنشور (title)، وسَيَأخِذُنا إلى posts/$postId، ونمرّر مُعرِّفِ المنشور الخاصّ بالمنشور

[06:46] الذي نحصل عليه في حلقتنا.

[06:49] غير أنّه يبدو أنّه لدينا خطأ.

[06:52] فلنُحدِّث (refresh) الصفحة ربّما.

[06:54] نعم. إذًا حين حدّثت، ها قد ظهر.

[06:56] فلدينا قائمة المنشورات هنا. وإذا نقرنا على أحد منشوراتنا فسَنتنقّل إلى posts/$postId، وفي هذا المسار يمكننا تحميل هذا المنشور بعينه.

[07:07] لكن فلنتركه على هذا الحال الآن، وسَنفعله لاحقًا.