Lifting State Up في React: مشاركة الحالة بين المكونات

أحيانًا يكون لديك مكوّنين يحتاجان نفس البيانات. إذا تركت كل مكوّن يدير حالته منفردًا، ستتكرر البيانات ولن تتزامن. الحل هو رفع الحالة (Lifting State Up).

ما معنى Lifting State Up؟

هو نقل الحالة إلى أقرب مكوّن أب مشترك، ثم تمريرها للمكونات الأبناء عبر Props.

التعريف البسيط: نضع الـ State في الأب بدل الابن لتشاركها عدة مكونات.

مثال بسيط: زر وتعداد

function CounterDisplay({ count }) {
  return <p>العدد: {count}</p>;
}

function CounterButtons({ onInc, onDec }) {
  return (
    <div>
      <button onClick={onInc}>+</button>
      <button onClick={onDec}>-</button>
    </div>
  );
}

function App() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <CounterDisplay count={count} />
      <CounterButtons
        onInc={() => setCount(count + 1)}
        onDec={() => setCount(count - 1)}
      />
    </div>
  );
}

هنا وضعنا الحالة في App، ثم مررنا القيمة إلى CounterDisplay والدوال إلى CounterButtons.

لماذا هذا مهم؟ لأن الزرّين هما من يغيّران القيمة، بينما العرض هو من يُظهرها. لو كانت الحالة داخل أحدهما فلن يستطيع الآخر الوصول لها. وضعناها في الأب ليتمكن الطرفان من المشاركة والتزامن دائمًا.

لماذا نرفع الحالة؟

  • لمنع تكرار البيانات.
  • لضمان أن كل المكونات تعرض نفس القيمة.
  • لتسهيل إدارة التحديثات في مكان واحد.

مثال عملي: فلتر المنتجات

function SearchBox({ query, onChange }) {
  return (
    <input
      value={query}
      onChange={(e) => onChange(e.target.value)}
      placeholder="ابحث عن منتج"
    />
  );
}

function ProductList({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  );
}

function App() {
  const [query, setQuery] = useState("");
  const items = [
    { id: 1, title: "Keyboard" },
    { id: 2, title: "Mouse" },
    { id: 3, title: "Monitor" }
  ];

  const filtered = items.filter((item) =>
    item.title.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <div>
      <SearchBox query={query} onChange={setQuery} />
      <ProductList items={filtered} />
    </div>
  );
}

هنا صندوق البحث لا يملك حالة داخلية، بل يعتمد على الحالة الموجودة في الأب. عند التغيير يتم تحديث القائمة مباشرة.

خطوة بخطوة: عندما يكتب المستخدم في SearchBox، نستدعي setQuery الموجودة في الأب. هذا يحدّث query، ثم يقوم الأب بحساب filtered وإرسالها إلى ProductList. النتيجة: القائمة تتغيّر فورًا حسب النص المدخل.

أخطاء شائعة

  • ترك الحالة في الابن ثم محاولة مشاركتها مع مكوّن آخر.
  • رفع الحالة أكثر من اللازم مما يجعل الكود معقّدًا.
  • تمرير Props بشكل عميق جدًا بدل استخدام Context.

الأسئلة الشائعة — FAQ

ما معنى Lifting State Up؟

هو نقل الحالة من مكوّن ابن إلى مكوّن أب لمشاركتها بين عدة مكونات.

متى أحتاج رفع الحالة؟

عندما تحتاج مكوّنات مختلفة نفس البيانات أو يجب أن تتزامن فيما بينها.

هل رفع الحالة أفضل من Context؟

في التطبيقات الصغيرة نعم، أما الكبيرة فـ Context أفضل لتجنب تمرير Props.

هل يجب رفع كل الحالات للأعلى؟

لا، فقط الحالات المشتركة. اترك الحالات المحلية في المكوّنات.

كيف أمرر الدالة من الأب للابن؟

عبر props، ثم يستدعيها الابن عند الحاجة.

التالي: سننتقل لدرس useContext لتجنب تمرير Props في السلاسل الطويلة.
المحرر الذكي

اكتب الكود وشاهد النتيجة فوراً

جرب الآن مجاناً
قناة ديف عربي

تابع أحدث الدروس والتحديثات مباشرة على واتساب

انضم الآن