مشاركة الحالة بين المكونات ورفع الحالة للأعلى (Lifting State Up)
| المفهوم الهندسي | الآلية البرمجية في React | النتيجة والتطبيق |
|---|---|---|
| مصدر الحقيقة الموحد Single Source of Truth | تجميع الحالة المشتركة في أقرب مكون أبن مشترك (Closest Common Ancestor) | منع تعارض البيانات واختلاف الحالة بين المكونات المجاورة في الواجهة |
| رفع الحالة Lifting State Up | تمرير الحالة عبر الـ Props وإرسال دوال التحديث كـ Callbacks للمكونات الأبناء | تمكين المكونات الفرعية من تعديل حالة الأب دون إخلال ببيئة تدفق البيانات |
| التدفق أُحادي الاتجاه Unidirectional Data Flow | هبوط البيانات من الأب للأبناء وصعود الأحداث من الأبناء للأب | جعل تتبع الأخطاء (Debugging) وسلوك التطبيق متوقعاً وسهلاً |
في كثير من الأحيان، تحتاج مكونات منفصلة في واجهة المستخدم إلى التفاعل مع نفس البيانات والتزامن معها. على سبيل المثال: عند تغيير العملة في شريط الملاحة الأعلى، يجب أن تتغير جميع أسعار الكورسات المعروضة في القائمة بالأسفل فوراً.
الخطأ الذي يقع فيه الكثير من المطورين هو إنشاء useState مستقلة داخل كل مكون على حدة، مما يؤدي إلى تشتت البيانات وعدم تزامنها.
تعتمد ريأكت على هيكلية شجرية (Component Tree). عندما تحتاج مكونات شقيقة (Sibling Components) إلى مشاركة البيانات، فإن القاعدة البرمجية تشترط رفع الحالة (Lifting State Up) إلى أقرب أب مشترك (Closest Common Ancestor) بينهما.
يستقبل القيمة عبر الـ Props ويعرضها دون معرفة كيفية إدارتها:
| 1 | // مكون يعرض السعر المحدد |
| 2 | function PriceDisplay({ price }) { |
| 3 | return <h3>السعر الحالي: {price} جنيه</h3>; |
| 4 | } |
يستقبل دالة التحديث (Callback Function) ويستدعيها عندما يتفاعل المستخدم:
| 1 | // مكون يحتوي على زر التخفيض |
| 2 | function DiscountButton({ onApplyDiscount }) { |
| 3 | return ( |
| 4 | <button onClick={() => onApplyDiscount(50)}> |
| 5 | تطبيق خصم 50 جنيه |
| 6 | </button> |
| 7 | ); |
| 8 | } |
هنا تعيش الحالة الحقيقية، ويتم توطين الدالة التي تغيرها ثم تمرير البيانات لجميع الأبناء:
| 1 | function CourseCard() { |
| 2 | const [price, setPrice] = useState(200); |
| 3 | |
| 4 | // دالة المعالجة التي سنمررها للابن |
| 5 | const handleDiscount = (amount) => { |
| 6 | setPrice((prev) => prev - amount); |
| 7 | }; |
| 8 | |
| 9 | return ( |
| 10 | <div> |
| 11 | {/* تمرير القيمة للابن الأول */} |
| 12 | <PriceDisplay price={price} /> |
| 13 | |
| 14 | {/* تمرير دالة التحديث للابن الثاني */} |
| 15 | <DiscountButton onApplyDiscount={handleDiscount} /> |
| 16 | </div> |
| 17 | ); |
| 18 | } |
تتبع ريأكت نظام حركة صارم جداً للبيانات يضمن عدم وجود عشوائية:
إذا وجدت نفسك تبني مكونين وتتساءل: "كيف أرسل بيانات من المكون A إلى المكون B المباشر الملازم له؟"