Props في React: تمرير البيانات وبناء مكونات قابلة لإعادة الاستخدام

بعد أن تعلمت إنشاء مكوّن، ستسأل: كيف أجعل نفس المكوّن يعرض بيانات مختلفة؟ هنا تأتي فكرة Props — وهي الطريقة الرسمية لتمرير البيانات بين المكونات.

بدون Props ستُضطر لتكرار نفس المكوّن مرات عديدة مع تغييرات بسيطة. أما مع Props، تكتب المكوّن مرة واحدة وتغذّيه بالبيانات التي تريد.

ما هي Props؟

Props اختصار لـ "Properties"، وهي قيم ترسلها من مكوّن أب إلى مكوّن ابن. بهذه الطريقة يصبح المكوّن قابلًا لإعادة الاستخدام مع بيانات مختلفة.

لماذا Props مهمة في المشاريع الحقيقية؟

  • تمنع تكرار الكود وتزيد من وضوح الواجهة.
  • تجعل المكوّنات مرنة وقابلة للتوسّع.
  • تُسهّل بناء صفحات مع بيانات متغيرة (منتجات، مقالات، مستخدمين).
التعريف البسيط: Props = قيم تمررها للمكوّن ليعرض محتوى مختلف.

قصة صغيرة: بطاقة منتج

تخيّل أنك تبني متجرًا يعرض عشرات المنتجات. هل ستكتب بطاقة لكل منتج يدويًا؟ بالطبع لا. تكتب مكوّنًا واحدًا ثم تمرّر له بيانات كل منتج عبر Props.

مثال بسيط (بطاقة منتج)

function ProductCard(props) {
  return (
    <div className="card">
      <h3>{props.title}</h3>
      <p>{props.price} MAD</p>
    </div>
  );
}

function App() {
  return (
    <div>
      <ProductCard title="Keyboard" price={299} />
      <ProductCard title="Mouse" price={99} />
    </div>
  );
}

في هذا المثال، المكوّن ProductCard يستقبل قيمتين عبر Props: title و price. عند استدعائه مرتين بقيم مختلفة، يعرض نفس التصميم مع بيانات مختلفة.

متى أستخدم Props ومتى أستخدم State؟

القاعدة البسيطة: إذا كانت البيانات تأتي من الخارج فهذه Props، وإذا كانت تتغير داخل المكوّن نفسه فهذه State.

طريقة أقصر باستخدام التفكيك

function ProductCard({ title, price }) {
  return (
    <div className="card">
      <h3>{title}</h3>
      <p>{price} MAD</p>
    </div>
  );
}

هنا استخدمنا التفكيك (Destructuring) لقراءة القيم مباشرة بدون كتابة props.title. النتيجة نفس المثال السابق لكن بكود أنظف وأقصر.

قاعدة مهمة: Props للقراءة فقط. لا تُعدّلها داخل المكوّن.

مثال: تمرير كائن عبر Props

أحيانًا يكون لديك بيانات كثيرة. بدل تمرير كل قيمة لوحدها، مرّر كائنًا كاملًا.

function UserCard({ user }) {
  return (
    <div className="card">
      <h3>{user.name}</h3>
      <p>{user.role}</p>
      <small>{user.email}</small>
    </div>
  );
}

function App() {
  const user = { name: \"Amina\", role: \"Designer\", email: \"a@site.com\" };
  return <UserCard user={user} />;
}

بدل تمرير كل قيمة لوحدها، مرّرنا كائن user كاملًا. هذا يفيد عندما تكون البيانات كثيرة أو مرتبطة ببعضها.

مثال: Props منطقية (Boolean)

function Button({ primary }) {
  const className = primary ? \"btn btn-primary\" : \"btn btn-outline-primary\";
  return <button className={className}>اشترك</button>;
}

function App() {
  return (
    <div>
      <Button primary />
      <Button />
    </div>
  );
}

مرّرنا primary للمكوّن Button، فغيّر المظهر بناءً على قيمتها. إذا كانت موجودة، يُستخدم زر أساسي، وإذا لم تُمرّر يعود للزر العادي.

مثال: قائمة عناصر باستخدام Props

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

function App() {
  const items = [
    { id: 1, title: \"Keyboard\" },
    { id: 2, title: \"Mouse\" }
  ];
  return <ProductList items={items} />;
}

هنا ProductList يستقبل مصفوفة عناصر عبر Props، ثم يعرضها باستخدام map مع key لكل عنصر.

تمرير محتوى داخل المكوّن: children

أحيانًا تحتاج مكونًا يلف محتوى مختلف. هنا نستخدم children.

function Card({ children }) {
  return <div className="card">{children}</div>;
}

function App() {
  return (
    <Card>
      <h3>عنوان مهم</h3>
      <p>أي محتوى يمكن وضعه هنا.</p>
    </Card>
  );
}

المكوّن Card يعمل كغلاف مرن. أي محتوى تضعه بين وسميه يتم تمريره تلقائيًا عبر children.

تمرير دالة عبر Props

غالبًا ستحتاج تمرير حدث من المكوّن الأب للمكوّن الابن.

function AddToCartButton({ onAdd }) {
  return <button onClick={onAdd}>أضف للسلة</button>;
}

function App() {
  function handleAdd() {
    alert(\"تمت الإضافة\");
  }

  return <AddToCartButton onAdd={handleAdd} />;
}

هنا الأب يمرّر دالة handleAdd للابن. عند الضغط، الابن ينفذ الدالة التي جاءت من الأب.

مثال: تمرير أكثر من دالة

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

function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>{count}</p>
      <CounterControls onInc={() => setCount(count + 1)} onDec={() => setCount(count - 1)} />
    </div>
  );
}

المكوّن CounterControls يستقبل دالتين: زيادة ونقصان. هذا يجعل المكوّن عامًا ويمكن استخدامه مع أي منطق عدّاد في أي مكان.

قيم افتراضية للـ Props

function Badge({ label = \"جديد\" }) {
  return <span className=\"badge\">{label}</span>;
}

إذا لم تمرّر قيمة، سيتم استخدام القيمة الافتراضية.

مثال: التحقق البسيط داخل المكوّن

function PriceTag({ price }) {
  if (price == null) return <span className=\"text-muted\">غير متوفر</span>;
  return <span>{price} MAD</span>;
}

نفحص وجود السعر قبل عرضه. إذا لم يُمرَّر، نعرض رسالة بدل رقم ناقص أو خطأ.

لماذا Props مهمة؟

  • تجعل المكونات قابلة لإعادة الاستخدام.
  • تسمح بفصل البيانات عن التصميم.
  • تُسهّل تنظيم الواجهة عندما تكبر.

أخطاء شائعة عند استخدام Props

  • تعديل Props داخل المكوّن: Props للقراءة فقط.
  • تمرير قيم بنوع خاطئ: مثال تمرير رقم كسلسلة نصية.
  • نسيان key في القوائم: مهم عند تمرير عناصر متعددة.

أخطاء شائعة

  • محاولة تعديل Props داخل المكوّن.
  • تمرير رقم كسلسلة نصية بالخطأ (مثال: price=\"99\" بدل price={99}).
  • نسيان تمرير قيمة مطلوبة فيظهر المكوّن ناقصًا.

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

ما هي Props في React؟

هي قيم تمرّرها من مكوّن أب إلى مكوّن ابن لعرض بيانات مختلفة.

هل يمكن تعديل Props داخل المكون؟

لا. Props ثابتة داخل المكوّن. للتعديل استخدم State في المكوّن الأب.

ما هي خاصية children؟

تسمح بتمرير محتوى داخل المكوّن بين وسمي الفتح والإغلاق ثم عرضه داخله.

كيف أمرّر دالة عبر Props؟

تمرّرها كقيمة عادية ثم تستدعيها داخل المكوّن عند الحدث المطلوب.

ما الفرق بين Props و State؟

Props تأتي من المكوّن الأب وهي للقراءة فقط، بينما State بيانات داخلية تتغير داخل المكوّن.

هل يمكن تمرير كائن أو مصفوفة عبر Props؟

نعم، يمكن تمرير أي قيمة JavaScript مثل كائن أو مصفوفة أو دالة عبر Props.

ما فائدة children في React؟

children تسمح بتمرير محتوى مختلف داخل نفس المكوّن ليعمل كغلاف مرن.

كيف أضع قيمة افتراضية للـ Props؟

يمكنك استخدام قيم افتراضية عبر التفكيك داخل تعريف المكوّن مثل {label = "جديد"}.

التالي: سننتقل لمفهوم State وكيف نجعل الواجهة تتغير مع الوقت.
المحرر الذكي

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

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

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

انضم الآن