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

إعادة هيكلة نموذجنا واستخدام useAppForm (Refactoring Our Form & Using useAppForm)

الدرس 16 من 21 · دورة TanStack Form الكاملة · 8 دقيقة و41 ثانية

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

مستودع شيفرة هذا الدرس

الفرع: useAppForm-1

[00:02] بمكوّناته قد يكون لدينا واجهة مستخدم ذات مظهر أجمل. غير أنّنا ما زلنا نواجه مشكلة مقدار الشيفرة التي اضطررنا إلى كتابتها كي ننشئ هذا النموذج البسيط. إذًا كما ترى هنا، فإنّ هذا الملف يضمّ ما يقارب خمسمئة أو أربعمئة سطر من الشيفرة.

[00:17] وإذا كان لديك تطبيق يضمّ كثيرًا من النماذج، أو نماذج كبيرة، فسيكون كتابةُ ذلك في كلّ مرّة أمرًا شاقًّا.

[00:23] فستكون مطَّلوبًا بأن تُصيّر مكوّناتك. وستضطرّ إلى تمرير هذه النداءات (callbacks) هكذا. وستضطرّ إلى تصيير الأخطاء هكذا وما إلى ذلك.

[00:33] وبالطبع، هذا لا يعقل.

[00:35] غير أنّ TanStack Form تتيح لنا — ولحسن الحظّ — وسيلةً تجعل نماذجنا أصغر بكثير. فدعنا نرَ كيف. لكن أولًا، فلنُنظِّف ربما الأشياء قليلًا. فعلى سبيل المثال، كنّا نطبع عبر console.log هذا الكائن values هنا. فلنقم ربما

[00:50] بإزالة هذا. ثم في الأعلى هنا، كنّا نعرّف مخطّطنا (schema) وقيمنا الافتراضية (default values). ومن الطَّبع يمكن أن تقرن هذه في ملفٍّ منفصل أيضًا. فدعنا نفعل ذلك. فإذًا في هنا سأقوم ربما بإنشاء مجلدٍ لأضع ملفاتٍ مختلفة

[01:06] في داخله. إذًا داخل هذا المجلد مثلًا لننشئ مجلدًا آخر. فربما لنسمّه register form أو أيّ اسمٍ ينبغي أن يكون لهذا النموذج.

[01:17] وداخل هذا لننشئ ملفًا خاصًّا بالأمور المشتركة. فإذًا في هنا سأنشئ ملفًا يُدعى shared.ts. وفلننقل في هنا أشياءنا التي ستُشاركها ملفاتٌ مختلفة في هذا مكوّن نموذج التسجيل داخل

[01:34] مجلد نموذج التسجيل. فعلى سبيل المثال: مخطّط النموذج، والقيم الافتراضية، وخيارات النموذج. فلننسخها أو لنُقصّها من هنا ولنضعها في هنا فحسب ولنُصدّرها. وبالطبع علينا أن نستورد

[01:50] Zod.

[01:52] ونحتاج كذلك إلى استيراد formOptions أيضًا.

[01:56] وفلنسمّه أيضًا ربما شيئًا أوضح: خيارات نموذج التسجيل (registerFormOptions).

[02:03] وفلنُصدّرها.

[02:06] وفلنُصدّر كذلك مخطّطنا وقيمنا الافتراضية هكذا.

[02:14] والآن فلنعد إلى مكوّن نموذج التسجيل لدينا ولنستورد هذه الأشياء. فإذًا في هنا فلنستورد registerFormOptions.

[02:23] في هنا. فلنستورد مخطّط النموذج (formSchema). وأظنّ أنّه يمكننا أيضًا أن نسمّيه مخطّطَ نموذجِ التسجيل (registerFormSchema) ونحدّث هذا أيضًا كي نكون أوضح فيما هو عليه هذا الشيء. فإذًا في هنا، فلنستورد registerFormSchema و

[02:40] نضعه في هنا أيضًا. وأظنّ أنّه إذا حفظنا هذا فسينبغي أن يعمل كلّ شيء.

[02:47] فإذًا إذا حدّثنا الصفحة، فلنحاول الإرسال، وكلّ شيء يعمل؛ فالتحقق من الصحة لدينا يعمل، ولذا يمكننا كذلك أن نزيل الاستيرادات التي لا نستخدمها الآن — فلم نعد نستخدم هذه الأشياء — وأظنّ أنّ الأمر بخير في الوقت الحالي. فلننقل أيضًا

[03:09] هذا المكوّن ربما إلى هذا المجلد كذلك، كي يكون كلّ ما لدينا يسكن في مجلد نموذج التسجيل هذا. غير أنّه بفعلنا ذلك، سيلزمنا الذهابُ إلى app.tsx والتأكّد من أنّ

[03:22] استيرادك قد حُدِّث الآن إلى هذا المسار. فدعنا نُحدِّث الصفحة.

[03:28] وينبغي أن يبقى كلّ شيء يعمل كالمعتاد. فإذًا كان ذلك قدرًا من التنظيم، لكن الآن فلنركّز على مشكلتنا الرئيسة.

[03:35] ما يلزمنا فعله الآن هو أنّنا كلّما احتجنا إلى إنشاء نموذج وتصيير حقلنا، احتجنا إلى أن نجد وسيلةً نجنّب بها الاضطرار إلى كتابة كلّ هذه الشيفرة القالبية (boilerplate) لمجرّد عرضنا للـ input وعرض الأخطاء الخاصة بـ

[03:47] input وهكذا. وما يمكننا فعله إذًا هو أنّه بدلًا من استخدام الخُطّاف useForm الذي توفّره TanStack Form يمكننا أن ننشئ خُطّافًا مخصّصًا، وهذا الخُطّاف المخصّص سيكون مسبقًا به مكوّناتنا، أي مكوّنات الـ input لدينا، معرَّفةً مسبقًا، و

[04:03] كلّ ما نفعله هنا. فإذًا عندما نمرّر قيمتنا، وonBlur خاصّتنا، وonChange خاصّتنا، وهلمّ جرًا، فكلّ ذلك سيكون معرَّفًا مسبقًا في هذا الخُطّاف المخصّص، ويمكننا ببساطة أن نستخدم مكوّن input لدينا دون الاضطرار إلى تمرير كلّ

[04:16] ذلك من الأشياء. فدعنا نرَ كيف يمكننا فعل ذلك. فإذًا في مجلدنا سأنشئ ربما — إذًا فلننشئ في مجلد src لدينا مجلدًا جديدًا. فلنسمّه hooks، ولننشئ هذا الخُطّاف المخصّص الذي هو بسيطٌ جدًّا. ولن

[04:31] نضطرّ في الواقع إلى أن نفعل كثيرًا من الأشياء بأنفسنا. فTanStack Form يوفّر لنا وسيلةً بسيطة لفعل ذلك. فإذًا ننشئ ملفًا جديدًا هنا. فربما لنسمّه form-context.tsx.

[04:43] ومن هنا سنحتاج إلى تصدير بعض الأشياء من دالةٍ يمكننا استيرادها من TanStack Form وهي createFormHookContexts. أليس كذلك؟

[04:57] فهذه الدالة ستُعيد بعض الأشياء يمكننا تفكيكها (destructure) من هنا، ومنها fieldContext وformContext وأيضًا useFieldContext وuseFormContext. و

[05:12] نحتاج إلى تصدير كلّ ذلك كي نستطيع استخدامه في ملفٍّ آخر. ففلنُصدّر إذًا كلّ ذلك. ففي جوهر الأمر، ما سنفعله هو أنّنا سنعرّف مكوّنات لنماذجنا. وعندما نعرّف مكوّنات لنماذجنا،

[05:25] كما ترى هنا، فإنّ داخل مكوّننا نحتاج إلى أن نكون قادرين على الوصول إلى الحقل، أليس كذلك؟ فهذا كي نعرض قيمة الحقل، وكي نمرّر onBlur وonChange وهلمّ جرًا، نحتاج إلى الوصول إلى الحقل. غير أنّنا الآن ونحن سننطلق في

[05:36] تعريف هذه المكوّنات في ملفاتٍ منفصلة كما سنرى الآن، فعلينا لأجل الوصول إلى هذا الحقل أن نفعل ذلك باستخدام هذا السياق (context) الموفَّر هنا. فإذًا fieldContext وuseFieldContext هما ما سيقدّمان لنا

[05:49] الوصول إلى حقولنا حين ننشئ مكوّناتٍ لمدخلاتنا. فإذا كان الأمر محيّرًا لديك، فسنرى كلّ شيء الآن. علينا الآن، بعد أن أنشأنا هذا المجلد وصدّرنا أشياءنا في مجلد hooks لدينا، الانتقال إلى

[06:03] إنشاء ملفٍّ آخر. فلنسمّه form.tsx.

[06:07] في هنا، يتعيّن علينا أن نعرّف خُطّافنا المخصّص الذي — كما ذكرنا — سنستخدمه بدلًا من هذا الخُطّاف useForm، أليس كذلك؟

[06:17] فإذًا في هنا، نحتاج إلى استدعاء دالةٍ تُدعى createFormHook هكذا.

[06:24] ثم يلزمنا تمرير بعض الأشياء إليها.

[06:26] ثم ستُعيد أيضًا بعض الأشياء.

[06:30] فما الذي يلزمنا تمريره إليها؟ نحتاج إلى تمرير السياق الذي صدّرناه في الملف الآخر؛ أي fieldContext. فإذًا fieldContext يساوي fieldContext الذي من الملف الذي أنشأناه للتوِّ. وكذلك

[06:45] formContext أيضًا.

[06:48] ويمكننا أن نمرّرَ كائنًا من مكوّنات الحقول (fieldComponents). فلنجعله في الوقت الحالي كائنًا فارغًا. ويمكننا أيضًا أن نملك مكوّنات نموذج (formComponents). أليس كذلك؟ فإذًا في هنا سنمرّر مختلف المكوّنات التي سنحتاج إلى استخدامها في نماذجنا.

[07:02] فعبر fieldComponents يمكننا تمرير الـ input لدينا، والـ checkbox لدينا، وهلمّ جرًا. وفي formComponents يمكن أن نجد أشياء مثل أزرار الإرسال — أشياء متعلّقة بالنموذج نفسه، لا بحقلٍ معيّن. وستتوفّر لنا أمثلة أيضًا. ثم

[07:15] ستُعيد هذه الدالة خُطّافنا المخصّص الذي يمكننا استخدامه، وهو يُدعى useAppForm. وستُعيد أيضًا withForm وwithFieldGroup وهما دالتان يمكن أن تساعدانا أيضًا ربما على تنظيم نموذجنا قليلًا.

[07:29] سنتناول هذه لاحقًا، لكن فلنركّز الآن على useAppForm. وفلنُصدِّر كذلك كلَّ ذلك من هذا الملف. والآن في نموذج التسجيل لدينا، بدلًا من استخدام useForm فلنستخدم useAppForm من مجلد hooks لدينا هكذا.

[07:48] فبفعلنا هذا لن يتغيّر شيء — بالطبع — في هذه اللحظة. غير أنّه الآن ما يمكننا فعله هو أنّه في هنا، عندما نستدعي createFormHook، يمكننا أن نعرّف هذه المكوّنات التي نستخدمها في نموذجنا هنا.

[08:02] فمثلًا مكوّن الـ input، ومكوّن الـ checkbox، وهلمّ جرًا. نعرّفها في ملفاتٍ منفصلة ثم نمرّرها إلى هذه الدالة عبر fieldComponents. وبفعلنا ذلك، وباستخدامنا هذا الخُطّاف useAppForm، لن نضطر إلى كتابة

[08:14] كلّ ذلك كلَّ مرّة. فستكون هذه المكوّنات معرَّفةً مسبقًا في هذا الخُطّاف.

[08:18] ويمكننا ببساطة أن نستخدمها بطريقةٍ أبسط بكثير من ذلك. وعندما نعرّف هذه المكوّنات، سنكون قادرين على الوصول إلى حقلنا؛ لأنّنا نمرّر fieldContext هنا أصلًا، وفي هنا نُصدّر

[08:32] دالة useFieldContext هذه. فإذًا باستخدام هذه الدالة سنحصل على الوصول إلى حقلنا عندما نعرّف مكوّننا. فلنرَ الآن كيف يمكننا تعريف مكوّناتنا المخصّصة. إذًا فلنبدأ ربما