في هذا الدرس 6تصفّح المواضيع
تنص القاعدة الثانية على منع الحالات المتناقضة. تخيل مكون طلب شراء يعرّف متغيرين منطقيين منفصلين isSubmitting وisSubmitted؛ فلو نسي المطور تصفير الأول في أحد المسارات فسيصبح الاثنان true في اللحظة نفسها، وهي حالة مستحيلة تعرض مؤشر الانتظار ورسالة النجاح معاً!
استبدل الرايات المتضاربة بمتغير حالة نصي واحد status يمثل المرحلة بدقة مثل 'typing' أو 'submitting' أو 'success'، واشتق الثوابت المنطقية المقروءة أثناء التصيير.
function PublishPanel() {
const [status, setStatus] = useState('draft');
const isPublishing = status === 'publishing';
const isPublished = status === 'published';
return (
<button disabled={isPublishing}
onClick={() => setStatus('published')}>
{isPublished ? 'Live!' : 'Publish Lesson'}
</button>
);
}
تركز القاعدة الثالثة على تجنب الحالة المكررة بحساب القيم المشتقة مباشرة. يقع المبتدئون كثيراً في فخ تخزين الاسم الأول والاسم الأخير ثم إضافة متغير حالة ثالث للاسم الكامل، أو حفظ مصفوفة المهام وبجانبها متغير حالة لعدد المهام المنجزة؛ ما يفرض عبء تحديث عدة متغيرات يدوياً في كل حدث.
متى أمكن استنتاج قيمة حسابياً من الحالة أو الخصائص الموجودة، احسبها كمتغير const عادي مباشرة أثناء التصيير دون استدعاء useState() جديد.
function CartSummary({ items }) {
const count = items.length;
const total = items.reduce((s, i) => s + i.price, 0);
const hasBonus = total >= 50;
return <p>{count} courses — Total: ${total}</p>;
}
تنص القاعدة الرابعة على منع تكرار الكائنات داخل الحالة. فلو كنت تبني قائمة دروس قابلة للتعديل وخزّنت المصفوفة lessons وبجانبها نسخة كاملة من الكائن المختار selectedLesson، فإن تعديل عنوان الدرس داخل المصفوفة سيترك الكائن المنسوخ حاملاً للعنوان القديم المتقادم!
الحل القياسي هو تخزين المعرّف فقط selectedId، ثم استخراج الكائن الحي في كل تصيير عبر lessons.find((l) => l.id === selectedId).
const [items, setItems] = useState(INITIAL_MODS);
const [selectedId, setSelectedId] = useState('m1');
const active = items.find((m) => m.id === selectedId);
أما القاعدة الخامسة فهي تجنب التداخل الهرمي العميق في الحالة. فتحديث عنصر مدفون على عمق أربع طبقات متداخلة يتطلب نسخ كل طبقة بمعامل الانتشار بالتتابع، ما يجعل الشفرة مطولة وعرضة للأخطاء.
يفضّل المهندسون تسطيح هيكل البيانات (Normalized State) عبر مصفوفة مسطحة يحمل كل عنصر فيها معرّف الأب parentId أو قاموس مفهرس بالمعرّفات، بحيث يتم أي تعديل بنسخ سطحي واحد نظيف.
وأخيراً، تجنب نسخ الخصائص القادمة من الأب داخل متغير حالة إلا إذا كنت تقصد عمداً تجاهل كل تحديث مستقبلي! فكتابة const [bg, setBg] = useState(color) تقرأ القيمة الابتدائية عند أول تصيير فقط، وإذا غيّر الأب خاصية color لاحقاً فستظل الحالة عالقة على اللون القديم.
استخدم الخاصية مباشرة في العرض، وإذا أردت قيمة ابتدائية لمرة واحدة فسمِّ الخاصية بوضوح initialColor. يجمع الجدول التالي القواعد الهندسية لتصميم الحالة:
| الخطأ المعماري في الحالة | المشكلة الناتجة في الواجهة | التصميم القياسي النظيف في React |
|---|---|---|
| رايات منطقية متعددة متضاربة | ظهور حالتين متناقضتين في اللحظة نفسها | متغير status نصي واحد واضح المراحل |
| تخزين المجاميع والفلاتر بالحالة | اختلاف الأرقام عند إضافة أو حذف عنصر | حساب القيم المشتقة مباشرة أثناء التصيير |
| نسخ الكائن المختار بالكامل | تقادم لوحة التفاصيل بعد تعديل العنصر | تخزين المعرّف selectedId والبحث بـ find |
| نسخ الخصائص داخل useState | تجاهل المكون الابن لتحديثات الأب اللاحقة | قراءة الخاصية القادمة من الأب مباشرة |
ملخص الدرس
حصاد الدرسمراجعة مركّزة لأهم المفاهيم والقواعد الهندسية التي أتقنتها في هذا الدرس قبل التطبيق العملي
ماذا تعلّمت في هذا الدرس؟
أتقنت في هذا الدرس القواعد المعمارية لتصميم الحالة في React: تجميع البيانات المتلازمة، واستبدال الرايات المتناقضة بمتغير مرحلة واحد، وحساب القيم المشتقة أثناء التصيير، وتخزين المعرّفات بدلاً من نسخ الكائنات، وتسطيح الشجرات العميقة وعدم نسخ الخصائص. الخطوة التالية: انتقل الآن إلى الدرس رقم 26 «رفع الحالة للأعلى وهوية بقاء أو تصفير الحالة» لمواصلة البناء التراكمي المتدرج في مسار React الحديث.
سجّل الدخول لحفظ تقدمك
تابع إنجاز المواضيع والمصطلحات والمهام، وكمّل من آخر خطوة على أي جهاز.
المصطلحات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 Derived Value القيمة المشتقة
- أي مجموع أو عداد أو قائمة مصفاة تُحسب لحظياً أثناء التصيير من الحالة أو الخصائص الموجودة.
- للمراجعة
- 02 Impossible State الحالة المستحيلة منطقياً
- اجتماع رايتين منطقيتين متناقضتين في وقت واحد كأن يكون الطلب قيد الإرسال ومكتمل النجاح معاً.
- للمراجعة
- 03 Normalized State الحالة المسطحة المنظمة
- تمثيل البيانات المتشعبة كمجموعات مسطحة مترابطة بالمعرّفات لتسهيل التحديث النقي دون تداخل عميق.
- للمراجعة
- 04 Prop Mirroring نسخ الخاصية في الحالة
- الخطأ المعماري المتمثل في تمرير خاصية الأب لـ useState مما يجمدها عند أول قيمة ويهمل تحديثات الأب.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
الاختصارات4
راجع المعنى، اشرحه لنفسك، ثم علّم البطاقة كمفهومة.
- 01 DRY DRY
- Don’t Repeat Yourself
- مبدأ عدم تكرار نفس المعلومة في أكثر من موضع والاكتفاء باشتقاق النتائج الحسابية منها.
- للمراجعة
- 02 ID ID
- Identifier
- معرّف فريد مختصر يُحفظ في الحالة لاسترجاع أحدث نسخة من الكائن داخل المصفوفة الأصلية.
- للمراجعة
- 03 UI UI
- User Interface
- طبقة العرض البصرية التي تبقى متسقة تلقائياً عند التخلص من متغيرات الحالة المكررة.
- للمراجعة
- 04 JSON JSON
- JavaScript Object Notation
- صيغة البيانات الشجرية التي يفضل المهندسون تسطيحها عند إدارة التعديلات المتداخلة في الحالة.
- للمراجعة
لا توجد بطاقات تطابق البحث والتصفية.
اقرأ البطاقات بحرية. سجّل الدخول لحفظ تقدم مراجعتك.
مهامك قبل الاختبار
خطوة صغيرة كل مرة. وإنجاز تقدر ترجع له.
-
افتح مثال DerivedCartDemo واحسب السعر بعد الخصم كمتغير مشتق أثناء التصيير دون إضافة أي متغير حالة جديد.
-
افتح مثال EditableModuleSelector وعدّل اسم الوحدة المختارة لتتأكد من تحديث المعاينة لحظياً بفضل تخزين المعرّف فقط.
تأشير المهمة إقرار منك بإتمامها، وليس تصحيحًا آليًا للكود. يُحفظ تقدمك في حسابك.
اختبر فهمك.
ووصلها للإتقان.
كل سؤال خطوة لقدّام. اختار، اكتب كود، وشوف نتيجتك فورًا.
أكمل المهام، واجمع كل الإجابات الصحيحة. أقل من 100%؟ راجع وأعد المحاولة.
الأسئلة متاحة للاطلاع. سجّل الدخول للتفاعل وحفظ تقدمك.
لمحة عن التحدي10 أسئلة تنتظرك +
متى يُفضّل جمع قيمتين معاً داخل كائن واحد في useState؟
القيم المتلازمة التي تتحدث دائماً في اللحظة نفسها مثل الإحداثيات أو العرض والارتفاع تُجمع في كائن واحد.
كيف تقضي على الحالات المتناقضة الناتجة عن تعدد الرايات المنطقية المنفصلة لحالة الإرسال؟
باستبدال الرايات المتفرقة بمتغير status نصي واحد يأخذ مرحلة واحدة محددة في كل وقت.
إذا كان المكون يملك الاسم الأول والأخير في الحالة، فما الطريقة الصحيحة للتعامل مع الاسم الكامل؟
حسابه كمتغير عادي أثناء التصيير مباشرة دون إنشاء متغير حالة ثالث مكرر.
تخزين مصفوفة عناصر السلة في الحالة مع إضافة متغير حالة منفصل لعددها يمثل تكراراً يعرض الواجهة لعدم التزامن.
صواب؛ لأن خاصية الطول للمصفوفة تعطي العدد الدقيق دائماً دون أي مخاطرة بنسيان التحديث.
في قائمة منتجات قابلة للتعديل تضم لوحة معاينة للمنتج المختار، ماذا يجب أن نخزن في الحالة لتمثيل الاختيار؟
تخزين المعرّف selectedId فقط والبحث عن المنتج الحي داخل المصفوفة أثناء التصيير.
ماذا يحدث إذا كتب المكون الابن useState(props.theme) ثم غيّر المكون الأب قيمة خاصية theme لاحقاً؟
تقرأ دالة useState القيمة الابتدائية عند التركيب الأول فقط فيتجاهل الابن التحديث الجديد القادم من الأب.
يسهم تسطيح هياكل الحالة شديدة التداخل إلى مجموعات مترابطة بالمعرّفات في جعل التحديثات النقية أقصر وأقل عرضة للأخطاء.
صواب؛ الهيكلة المسطحة تغني عن نسخ أربع أو خمس طبقات متداخلة في كل تعديل بسيط.
عندما تقصد عمداً استخدام خاصية الأب كقيمة بذرة أولية فقط لحالة محلية مستقلة، فما التسمية التوضيحية الموصى بها؟
بدء اسم الخاصية ببادئة مثل initialTitle أو defaultColor لتوضيح أنها تُقرأ في البداية فقط.
يمكن اشتقاق متغيرات منطقية مقروءة مثل isSending مباشرة أثناء التصيير من متغير المرحلة النصي الموحد status.
صواب؛ تجمع بذلك بين وضوح القراءة في JSX واستحالة تناقض الحالة.
ما القاعدة الذهبية التي تلخص فلسفة تقليل متغيرات الحالة في React؟
تخزين الحد الأدنى الضروري من البيانات الأولية المتغيرة واشتقاق كل ما عداها أثناء التصيير.