أطلق العنان للتحقق القوي والحديث من صحة النماذج في React. يستكشف هذا الدليل الشامل خطاف `experimental_useFormStatus` وإجراءات الخادم ونموذج التحقق المعتمد على الحالة لبناء نماذج قوية وعالية الأداء.
إتقان التحقق من صحة النماذج باستخدام خطاف `experimental_useFormStatus` في React
تعتبر النماذج حجر الأساس للتفاعل على الويب. من اشتراك بسيط في نشرة إخبارية إلى تطبيق مالي معقد متعدد الخطوات، فهي القناة الرئيسية التي يتواصل من خلالها المستخدمون مع تطبيقاتنا. ومع ذلك، لسنوات، كانت إدارة حالة النماذج في React مصدرًا للتعقيد، والتعليمات البرمجية المتكررة، والإرهاق من الاعتماديات. لقد تعاملنا مع المكونات المتحكم بها، وصارعنا مكتبات إدارة الحالة، وكتبنا عددًا لا يحصى من معالجات `onChange`، كل ذلك سعيًا وراء تجربة مستخدم سلسة وبديهية.
كان فريق React يعيد التفكير في هذا الجانب الأساسي من تطوير الويب، مما أدى إلى تقديم نموذج جديد وقوي يتمحور حول إجراءات خادم React (React Server Actions). يهدف هذا النموذج الجديد، المبني على مبادئ التحسين التدريجي، إلى تبسيط التعامل مع النماذج عن طريق نقل المنطق إلى مكان أقرب إلى حيث ينتمي - غالبًا، الخادم. وفي قلب هذه الثورة من جانب العميل يوجد خطافان تجريبيان جديدان: `useFormState` ونجم مناقشتنا اليوم، `experimental_useFormStatus`.
سيأخذك هذا الدليل الشامل في رحلة عميقة إلى خطاف `experimental_useFormStatus`. لن نقتصر على النظر في بنيته فحسب؛ بل سنستكشف النموذج الذهني الذي يتيحه: منطق التحقق المعتمد على الحالة (Status-Based Validation Logic). ستتعلم كيف يفصل هذا الخطاف واجهة المستخدم عن حالة النموذج، ويبسط إدارة حالات الانتظار، ويعمل بالتنسيق مع إجراءات الخادم لإنشاء نماذج قوية وسهلة الوصول وعالية الأداء تعمل حتى قبل تحميل JavaScript. استعد لإعادة التفكير في كل ما كنت تعتقده حول بناء النماذج في React.
تحول نموذجي: تطور النماذج في React
لتقدير الابتكار الذي يجلبه `useFormStatus` تمامًا، يجب علينا أولاً فهم رحلة إدارة النماذج في نظام React البيئي. يسلط هذا السياق الضوء على المشكلات التي يحلها هذا النهج الجديد بأناقة.
الحرس القديم: المكونات المتحكم بها والمكتبات الخارجية
لسنوات، كان النهج القياسي للنماذج في React هو نمط المكون المتحكم به (controlled component). يتضمن هذا:
- استخدام متغير حالة في React (على سبيل المثال، من `useState`) للاحتفاظ بقيمة كل حقل إدخال في النموذج.
- كتابة معالج `onChange` لتحديث الحالة عند كل ضغطة مفتاح.
- تمرير متغير الحالة مرة أخرى إلى خاصية `value` الخاصة بالمدخل.
بينما يمنح هذا React السيطرة الكاملة على حالة النموذج، فإنه يقدم كمية كبيرة من التعليمات البرمجية المتكررة. بالنسبة لنموذج يحتوي على عشرة حقول، قد تحتاج إلى عشرة متغيرات حالة وعشر وظائف معالجة. وتضيف إدارة التحقق من الصحة وحالات الخطأ وحالة الإرسال مزيدًا من التعقيد، مما يدفع المطورين غالبًا إلى إنشاء خطافات مخصصة معقدة أو اللجوء إلى مكتبات خارجية شاملة.
برزت مكتبات مثل Formik و React Hook Form من خلال تجريد هذا التعقيد. إنها توفر حلولًا رائعة لإدارة الحالة والتحقق من الصحة وتحسين الأداء. ومع ذلك، فإنها تمثل اعتمادية أخرى يجب إدارتها وغالبًا ما تعمل بالكامل على جانب العميل، مما قد يؤدي إلى تكرار منطق التحقق بين الواجهة الأمامية والخلفية.
العصر الجديد: التحسين التدريجي وإجراءات الخادم
تقدم إجراءات خادم React تحولًا نموذجيًا. الفكرة الأساسية هي البناء على أساس منصة الويب: عنصر HTML القياسي `
مثال بسيط: زر الإرسال الذكي
دعنا نرى حالة الاستخدام الأكثر شيوعًا في العمل. بدلاً من `
ملف: SubmitButton.js
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
export function SubmitButton() {
const { pending } = useFormStatus();
return (
);
}
ملف: SignUpForm.js
import { SubmitButton } from './SubmitButton';
import { signUpAction } from './actions'; // إجراء خادم
export function SignUpForm() {
return (
في هذا المثال، `SubmitButton` مستقل تمامًا. لا يتلقى أي خصائص. يستخدم `useFormStatus` لمعرفة متى يكون `SignUpForm` في حالة انتظار ويقوم تلقائيًا بتعطيل نفسه وتغيير نصه. هذا نمط قوي للفصل وإنشاء مكونات قابلة لإعادة الاستخدام ومدركة للنماذج.
جوهر المسألة: منطق التحقق المعتمد على الحالة
نصل الآن إلى المفهوم الأساسي. `useFormStatus` ليس فقط لحالات التحميل؛ إنه عامل تمكين رئيسي لطريقة مختلفة للتفكير في التحقق من الصحة.
تعريف "التحقق المعتمد على الحالة"
التحقق المعتمد على الحالة هو نمط يتم فيه تقديم ملاحظات التحقق للمستخدم بشكل أساسي استجابةً لمحاولة إرسال النموذج. بدلاً من التحقق عند كل ضغطة مفتاح (`onChange`) أو عندما يغادر المستخدم حقلاً (`onBlur`)، يعمل منطق التحقق الأساسي عند إرسال المستخدم للنموذج. ثم يتم استخدام نتيجة هذا الإرسال — أي *حالتها* (على سبيل المثال، نجاح، خطأ في التحقق، خطأ في الخادم) — لتحديث واجهة المستخدم.
يتوافق هذا النهج تمامًا مع إجراءات خادم React. يصبح إجراء الخادم المصدر الوحيد للحقيقة للتحقق. يتلقى بيانات النموذج، ويتحقق منها مقابل قواعد عملك (على سبيل المثال، "هل هذا البريد الإلكتروني مستخدم بالفعل؟")، ويعيد كائن حالة منظمًا يشير إلى النتيجة.
دور شريكه: `experimental_useFormState`
يخبرنا `useFormStatus` *بما* يحدث (قيد الانتظار)، لكنه لا يخبرنا *بنتيجة* ما حدث. لذلك، نحتاج إلى خطافه الشقيق: `experimental_useFormState`.
`useFormState` هو خطاف مصمم لتحديث الحالة بناءً على نتيجة إجراء النموذج. يأخذ دالة الإجراء وحالة أولية كوسائط ويعيد حالة جديدة ودالة إجراء مغلفة لتمريرها إلى النموذج الخاص بك.
const [state, formAction] = useFormState(myAction, initialState);
- `state`: سيحتوي هذا على القيمة المرجعة من آخر تنفيذ لـ `myAction`. هذا هو المكان الذي سنحصل منه على رسائل الخطأ الخاصة بنا.
- `formAction`: هذه نسخة جديدة من الإجراء الخاص بك يجب أن تمررها إلى خاصية `action` الخاصة بـ `
`. عند استدعاء هذا، سيؤدي إلى تشغيل الإجراء الأصلي وتحديث `state`.
سير العمل المشترك: من النقر إلى الملاحظات
إليك كيفية عمل `useFormState` و `useFormStatus` معًا لإنشاء حلقة تحقق كاملة:
- العرض الأولي: يتم عرض النموذج بحالة أولية مقدمة من `useFormState`. لا تظهر أي أخطاء.
- إرسال المستخدم: ينقر المستخدم على زر الإرسال.
- حالة الانتظار: يقوم خطاف `useFormStatus` في زر الإرسال بالإبلاغ فورًا عن `pending: true`. يصبح الزر معطلاً ويعرض رسالة تحميل.
- تنفيذ الإجراء: يتم تنفيذ إجراء الخادم (المغلف بواسطة `useFormState`) مع بيانات النموذج. ويقوم بالتحقق من الصحة.
- إرجاع الإجراء: يفشل الإجراء في التحقق ويعيد كائن حالة، على سبيل المثال:
`{ message: "فشل التحقق", errors: { email: "هذا البريد الإلكتروني مسجل بالفعل." } }` - تحديث الحالة: يتلقى `useFormState` هذه القيمة المرجعة ويحدث متغير `state` الخاص به. يؤدي هذا إلى إعادة عرض مكون النموذج.
- ملاحظات واجهة المستخدم: يتم إعادة عرض النموذج. تصبح حالة `pending` من `useFormStatus` `false`. يمكن للمكون الآن قراءة `state.errors.email` وعرض رسالة الخطأ بجوار حقل إدخال البريد الإلكتروني.
يوفر هذا التدفق بأكمله ملاحظات واضحة وموثوقة من الخادم للمستخدم، مدفوعة بالكامل بحالة ونتيجة الإرسال.
درس عملي متقدم: بناء نموذج تسجيل متعدد الحقول
دعنا نرسخ هذه المفاهيم من خلال بناء نموذج تسجيل كامل على غرار الإنتاج. سنستخدم إجراء خادم للتحقق وكلًا من `useFormState` و `useFormStatus` لإنشاء تجربة مستخدم رائعة.
الخطوة 1: تحديد إجراء الخادم مع التحقق من الصحة
أولاً، نحتاج إلى إجراء الخادم الخاص بنا. للتحقق القوي، سنستخدم المكتبة الشهيرة Zod. سيعيش هذا الإجراء في ملف منفصل، مميزًا بتوجيه `'use server';` إذا كنت تستخدم إطار عمل مثل Next.js.
ملف: actions/authActions.js
'use server';
import { z } from 'zod';
// تحديد مخطط التحقق
const registerSchema = z.object({
username: z.string().min(3, 'يجب أن يتكون اسم المستخدم من 3 أحرف على الأقل.'),
email: z.string().email('الرجاء إدخال عنوان بريد إلكتروني صالح.'),
password: z.string().min(8, 'يجب أن تتكون كلمة المرور من 8 أحرف على الأقل.'),
});
// تحديد الحالة الأولية للنموذج
export const initialState = {
message: '',
errors: {},
};
export async function registerUser(prevState, formData) {
// 1. التحقق من صحة بيانات النموذج
const validatedFields = registerSchema.safeParse(
Object.fromEntries(formData.entries())
);
// 2. إذا فشل التحقق، قم بإرجاع الأخطاء
if (!validatedFields.success) {
return {
message: 'فشل التحقق. يرجى التحقق من الحقول.',
errors: validatedFields.error.flatten().fieldErrors,
};
}
// 3. (محاكاة) التحقق مما إذا كان المستخدم موجودًا بالفعل في قاعدة البيانات
// في تطبيق حقيقي، ستقوم بالاستعلام من قاعدة بياناتك هنا.
if (validatedFields.data.email === 'user@example.com') {
return {
message: 'فشل التسجيل.',
errors: { email: ['هذا البريد الإلكتروني مسجل بالفعل.'] },
};
}
// 4. (محاكاة) إنشاء المستخدم
console.log('Creating user:', validatedFields.data);
// 5. إرجاع حالة نجاح
// في تطبيق حقيقي، قد تقوم بإعادة التوجيه هنا باستخدام `redirect()` من 'next/navigation'
return {
message: 'تم تسجيل المستخدم بنجاح!',
errors: {},
};
}
إجراء الخادم هذا هو عقل نموذجنا. إنه مستقل، آمن، ويوفر بنية بيانات واضحة لكل من حالات النجاح والخطأ.
الخطوة 2: بناء مكونات قابلة لإعادة الاستخدام ومدركة للحالة
للحفاظ على نظافة مكون النموذج الرئيسي، سنقوم بإنشاء مكونات مخصصة لمدخلاتنا وزر الإرسال.
ملف: components/SubmitButton.js
'use client';
import { experimental_useFormStatus as useFormStatus } from 'react-dom';
export function SubmitButton({ label }) {
const { pending } = useFormStatus();
return (
);
}
لاحظ استخدام `aria-disabled={pending}`. هذه ممارسة مهمة لإمكانية الوصول، مما يضمن أن قارئات الشاشة تعلن عن الحالة المعطلة بشكل صحيح.
الخطوة 3: تجميع النموذج الرئيسي باستخدام `useFormState`
الآن، دعنا نجمع كل شيء معًا في مكون النموذج الرئيسي. سنستخدم `useFormState` لربط واجهة المستخدم الخاصة بنا بإجراء `registerUser`.
ملف: components/RegistrationForm.js
{state.message} {state.message}
{state.errors.username[0]}
{state.errors.email[0]}
{state.errors.password[0]}
'use client';
import { experimental_useFormState as useFormState } from 'react-dom';
import { registerUser, initialState } from '../actions/authActions';
import { SubmitButton } from './SubmitButton';
export function RegistrationForm() {
const [state, formAction] = useFormState(registerUser, initialState);
return (
تسجيل
{state?.message && !state.errors &&
هذا المكون الآن تعبيري ونظيف. لا يدير أي حالة بنفسه، باستثناء كائن `state` الذي يوفره `useFormState`. وظيفته الوحيدة هي عرض واجهة المستخدم بناءً على تلك الحالة. يتم تغليف منطق تعطيل الزر في `SubmitButton`، وجميع منطق التحقق يعيش في `authActions.js`. هذا الفصل بين الاهتمامات هو فوز كبير للصيانة.
تقنيات متقدمة وأفضل الممارسات المهنية
بينما يكون النمط الأساسي قويًا، فإن التطبيقات الواقعية تتطلب غالبًا المزيد من الدقة. دعنا نستكشف بعض التقنيات المتقدمة.
النهج الهجين: دمج التحقق الفوري والتحقق بعد الإرسال
التحقق المعتمد على الحالة ممتاز للتحققات من جانب الخادم، ولكن انتظار رحلة ذهاب وعودة عبر الشبكة لإخبار المستخدم بأن بريده الإلكتروني غير صالح يمكن أن يكون بطيئًا. غالبًا ما يكون النهج الهجين هو الأفضل:
- استخدم التحقق من صحة HTML5: لا تنس الأساسيات! توفر السمات مثل `required` و `type="email"` و `minLength` و `pattern` ملاحظات فورية أصلية للمتصفح دون أي تكلفة.
- التحقق الخفيف من جانب العميل: للفحوصات التجميلية أو التنسيقية البحتة (مثل مؤشر قوة كلمة المرور)، لا يزال بإمكانك استخدام كمية قليلة من `useState` ومعالجات `onChange`.
- سلطة جانب الخادم: احتفظ بإجراء الخادم للتحقق الأكثر أهمية ومنطق الأعمال الذي لا يمكن القيام به على العميل (مثل التحقق من أسماء المستخدمين الفريدة، والتحقق من سجلات قاعدة البيانات).
يمنحك هذا أفضل ما في العالمين: ملاحظات فورية للأخطاء البسيطة وتحقق موثوق للقواعد المعقدة.
إمكانية الوصول (A11y): بناء نماذج للجميع
إمكانية الوصول غير قابلة للتفاوض. عند تنفيذ التحقق المعتمد على الحالة، ضع هذه النقاط في اعتبارك:
- الإعلان عن الأخطاء: في مثالنا، استخدمنا `aria-live="polite"` على حاويات رسائل الخطأ. يخبر هذا قارئات الشاشة بالإعلان عن رسالة الخطأ بمجرد ظهورها، دون مقاطعة تدفق المستخدم الحالي.
- ربط الأخطاء بالمدخلات: للحصول على اتصال أكثر قوة، استخدم السمة `aria-describedby`. يمكن للمدخل أن يشير إلى معرف حاوية رسالة الخطأ الخاصة به، مما ينشئ رابطًا برمجيًا.
- إدارة التركيز: بعد إرسال يحتوي على أخطاء، فكر في نقل التركيز برمجيًا إلى أول حقل غير صالح. هذا يوفر على المستخدمين عناء البحث عما حدث من خطأ.
واجهة المستخدم المتفائلة مع خاصية `data` في `useFormStatus`
تخيل تطبيق وسائط اجتماعية حيث ينشر المستخدم تعليقًا. بدلاً من إظهار مؤشر تحميل لمدة ثانية، يمكنك جعل التطبيق يبدو فوريًا. خاصية `data` من `useFormStatus` مثالية لهذا الغرض.
عند إرسال النموذج، تصبح `pending` `true` ويتم ملء `data` بـ `FormData` للإرسال. يمكنك على الفور عرض التعليق الجديد في حالة مرئية مؤقتة 'قيد الانتظار' باستخدام هذه `data`. إذا نجح إجراء الخادم، فإنك تستبدل التعليق المعلق بالبيانات النهائية من الخادم. إذا فشل، يمكنك إزالة التعليق المعلق وإظهار خطأ. هذا يجعل التطبيق يبدو سريع الاستجابة بشكل لا يصدق.
الإبحار في مياه "التجريبية"
من الأهمية بمكان معالجة البادئة "experimental" في `experimental_useFormStatus` و `experimental_useFormState`.
ماذا تعني "تجريبية" حقًا
عندما تصف React واجهة برمجة تطبيقات بأنها تجريبية، فهذا يعني:
- قد تتغير واجهة برمجة التطبيقات: قد يتم تغيير الاسم أو الوسائط أو القيم المرجعة في إصدار مستقبلي من React دون اتباع الإصدار الدلالي القياسي (SemVer) للتغييرات الكاسرة.
- قد تكون هناك أخطاء: كميزة جديدة، قد تحتوي على حالات حافة لم يتم فهمها أو حلها بالكامل بعد.
- قد تكون الوثائق متفرقة: بينما يتم توثيق المفاهيم الأساسية، قد لا تزال الأدلة التفصيلية حول الأنماط المتقدمة قيد التطوير.
متى تتبنى ومتى تنتظر
إذًا، هل يجب عليك استخدامه في مشروعك؟ تعتمد الإجابة على سياقك:
- جيد لـ: المشاريع الشخصية، الأدوات الداخلية، الشركات الناشئة، أو الفرق التي تشعر بالراحة في إدارة التغييرات المحتملة في واجهة برمجة التطبيقات. يعد استخدامه ضمن إطار عمل مثل Next.js (الذي قام بدمج هذه الميزات في App Router الخاص به) رهانًا أكثر أمانًا بشكل عام، حيث يمكن لإطار العمل المساعدة في تجريد بعض التغييرات.
- استخدم بحذر لـ: تطبيقات الشركات الكبيرة، الأنظمة ذات الأهمية الحيوية، أو المشاريع ذات عقود الصيانة طويلة الأجل حيث يكون استقرار واجهة برمجة التطبيقات أمرًا بالغ الأهمية. في هذه الحالات، قد يكون من الحكمة الانتظار حتى يتم ترقية الخطافات إلى واجهة برمجة تطبيقات مستقرة.
راقب دائمًا مدونة React الرسمية والوثائق للحصول على إعلانات بشأن استقرار هذه الخطافات.
الخاتمة: مستقبل النماذج في React
إن إدخال `experimental_useFormStatus` وواجهات برمجة التطبيقات ذات الصلة هو أكثر من مجرد أداة جديدة؛ إنه يمثل تحولًا فلسفيًا في كيفية بناء تجارب تفاعلية مع React. من خلال تبني أسس منصة الويب وتحديد موقع المنطق ذي الحالة على الخادم، يمكننا بناء تطبيقات أبسط وأكثر مرونة وغالبًا ما تكون أكثر أداءً.
لقد رأينا كيف يوفر `useFormStatus` طريقة نظيفة ومنفصلة للمكونات للتفاعل مع دورة حياة إرسال النموذج. إنه يزيل تمرير الخصائص للحالات المعلقة ويمكّن من إنشاء مكونات واجهة مستخدم أنيقة ومستقلة مثل `SubmitButton` الذكي. عند دمجه مع `useFormState`، فإنه يطلق العنان للنمط القوي للتحقق المعتمد على الحالة، حيث يكون الخادم هو السلطة النهائية، وتكون المسؤولية الرئيسية للعميل هي عرض الحالة التي يتم إرجاعها بواسطة إجراء الخادم.
بينما تستدعي علامة "تجريبي" درجة من الحذر، فإن الاتجاه واضح. مستقبل النماذج في React هو مستقبل التحسين التدريجي، وإدارة الحالة المبسطة، والتكامل القوي والسلس بين منطق العميل والخادم. من خلال إتقان هذه الخطافات الجديدة اليوم، فإنك لا تتعلم فقط واجهة برمجة تطبيقات جديدة؛ بل تستعد للجيل القادم من تطوير تطبيقات الويب باستخدام React.