تمرير الخصائص إلى مكوّن

تستخدم مكوّنات React “الخصائص” (props) للتواصل مع بعضها البعض. يمكن لكل مكوّن أب تمرير بعض المعلومات إلى مكوّناته الفرعية عن طريق إعطائها الخصائص. قد تذكرك الخصائص بسمات HTML، ولكن يمكنك تمرير أي قيمة JavaScript من خلالها، بما في ذلك الكائنات والمصفوفات والدوال.

You will learn

  • كيفية تمرير الخصائص (props) إلى المكوّنات (Components)
  • كيفية قراءة الخصائص من مكوّن
  • كيفية تحديد القيم الافتراضية للخصائص
  • كيفية تمرير بعض عناصر JSX إلى مكوّن
  • كيف تتغير الخصائص مع مرور الوقت

الخصائص المألوفة

الخصائص هي المعلومات التي تمررها إلى وسم JSX . على سبيل المثال، className، src، alt، width، و height هي بعض الخصائص التي يمكنك تمريرها إلى <img>:

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  );
}

export default function Profile() {
  return (
    <Avatar />
  );
}

الخصائص التي يمكن تمريرها إلى وسم <img> هي خصائص محدده مسبقًا (ReactDOM يتوافق مع معيار الHTML). ولكن يمكنك تمرير أي خصائص إلى المكوّنات الخاصة بك، مثل <Avatar>، لتخصيصها. هنا كيفية ذلك!

تمرير الخصائص إلى مكوّن

في هذا الكود، مكوّن ال Profile لا يمرر أي خصائص إلى مكوّنه الطفل، Avatar:

export default function Profile() {
return (
<Avatar />
);
}

يمكنك إعطاء Avatar بعض الخصائص في خطوتين.

الخطوة الأولى: تمرير الخصائص إلى مكوّن طفل

أولاً، يجب تمرير بعض الخصائص إلى Avatar. على سبيل المثال، دعونا نمرر خاصيتين: person (كائن)، و size (رقم):

export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying'، imageId: '1bX5QH6' }}
size={100}
/>
);
}

Note

إذا كنت تشعر بالحيرة بسبب تكرار الأقواس المنحنية بعد person=، فتذكر أنها مجرد كائن داخل الأقواس المنحنية (curlies) في JSX

الآن يمكنك قراءة هذه الخصائص داخل مكوّن الAvatar.

الخطوة الثانية: اقرأ الخصائص داخل المكّون الطفل

يمكنك قراءة هذه الخصائص عن طريق كتابة أسمائها person, size مفصولة بفواصل داخل ({ و }) مباشرة بعد function Avatar. هذا يتيح لك استخدامها داخل كود Avatar، كما تفعل مع المتغيرات.

function Avatar({ person, size }) {
// person و size متاحين هنا
}

أضف بعض المنطق إلى Avatar باستخدام الخصائص person و size للتصيير، وبذلك تكون انتهيت.

الآن يمكنك تهيئة Avatar للتصيير بطرق مختلفة مع خصائص مختلفة. جرب تعديل القيم!

import { getImageUrl } from './utils.js';

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{ 
          name: 'كاتسوكو ساروهاشي', 
          imageId: 'YfeOqp2'
        }}
      />
      <Avatar
        size={80}
        person={{
          name: 'أكليلو ليما', 
          imageId: 'OKS67lh'
        }}
      />
      <Avatar
        size={50}
        person={{ 
          name: 'لين لانين',
          imageId: '1bX5QH6'
        }}
      />
    </div>
  );
}

تتيح لك المكوّنات التفكير في المكوّنات الآباء والمكوّنات الأبناء بشكل مستقل. على سبيل المثال، يمكنك تغيير مكوّنات الperson أو الsize في داخل Profile دون الحاجة للتفكير في كيفية استخدامهما في المكوّن المسمى Avatar. بالمثل، يمكنك تغيير كيفية استخدام المكوّن Avatar لهذه الخصائص دون النظر إلى المكوّن Profile.

يمكنك التفكير في الخصائص على أنها “أدوات تعديل” يمكنك تعديلها. إنها تؤدي نفس الدور الذي تؤديه الوسائط للدوال - في الواقع، الخصائص هي الوسيطة الوحيدة لمكوّنك! تقبل دوال المكوّنات في React وسيطة واحدة فقط، كائن خصائص

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

عادةً ما لا تحتاج إلى كامل كائن الprops نفسه، لذلك يتم تحليله إلى خصائص فردية.

Pitfall

لا تنسى زوجي { و } الأقواس المنحنية داخل ( و ) عند إعلان الخصائص:

function Avatar({ person, size }) {
// ...
}

هذه الصيغة تسمى “تحليل” وهي ما تعادل قراءة الخصائص من عامل الدالة:

function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}

تحديد قيمة افتراضية لخاصية

إذا كنت تريد إعطاء قيمة افتراضية لخاصية تستخدم عند عدم تحديد قيمة، يمكنك القيام بذلك باستخدام الصيغة التحليلية عن طريق وضع علامة = والقيمة الافتراضية مباشرة بعد المعامل:

function Avatar({ person, size = 100 }) {
// ...
}

الآن، إذا تم عرض <Avatar person={...} /> بدون خاصية size،سيتم تعيين الsize على 100.

تُستخدم القيمة الافتراضية فقط إذا كانت خاصية الsize مفقودة أو إذا قمت بتمرير size={undefined}. ولكن إذا قمت بتمرير size={null} أو size={0}، فلن يتم استخدام القيمة الافتراضية.

إعادة توجيه الخصائص باستخدام صيغة الانتشار (spread operator) في JSX

في بعض الأحيان، يصبح تمرير الخصائص مُكررًا جدًا:

function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}

لا يوجد أي شيء خاطئ في تكرار الكود - بل يمكن أن يزيد الوضوح. ولكن في بعض الأحيان قد يُفَضّل الاختصار. تقوم بعض المكوّنات بتوجيه جميع خصائصها إلى أطفالها، مثل الطريقة التي يفعل بها Profile مع Avatar. نظرًا لعدم استخدامها لأي من خصائصها مباشرة، فقد يكون من المنطقي استخدام صيغة الانتشار “spread” الأكثر اختصارًا:

function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}

يقوم هذا بتوجيه جميع خصائص Profile إلى Avatar دون تسمية كل منها بشكل فردي.

استخدم صيغة انتشار بحذر. إذا كنت تستخدمها في كل مكوّن آخر، فهناك شيء خاطئ. غالبًا ما يشير ذلك إلى أنه يجب تقسيم المكوّنات الخاصة بك وتمرير الأطفال كـ JSX. المزيد حول ذلك في القسم التالي!

تمرير JSX كأطفال

من الشائع تضمين أوسمّة المتصفح المدمجة:

<div>
<img />
</div>

في بعض الأحيان ستريد تضمين مكوّناتك الخاصة بنفس الطريقة:

<Card>
<Avatar />
</Card>

عند تضمين محتوى داخل وسم JSX، سيتلقى المكوّن الأب هذا المحتوى في خاصية تسمى children. على سبيل المثال، سيتلقى المكوّن Card القادم خاصية children التي تم تعيينها على <Avatar /> و يقوم بعرضها في قسم مجمع

import Avatar from './Avatar.js';

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

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{ 
          name: 'كاتسوكو ساروهاشي',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

جرب استبدال <Avatar> داخل <Card> بنص ما لمعرفة كيف يمكن للمكوّن Card لف أي محتوى متداخل. لا يحتاج المكوّن إلى “معرفة” ما يتم تقديمه داخله. سترى هذه النمط المرن في العديد من الأماكن.

يمكنك التفكير في المكوّن الذي يحتوي على خاصية children على أنه لديه “ثقب” يمكن “ملؤه” من قِبَل مكوّناته الأبويه بأي JSX. سوف تستخدم في كثير من الأحيان خاصية children للتغليف البصري: اللوحات، الشبكات، إلخ.

A puzzle-like Card tile with a slot for "children" pieces like text and Avatar

Illustrated by Rachel Lee Nabors

كيفية تغيير الخصائص مع مرور الوقت

يتلقى المكوّن Clock القادم خاصيتين من مكوّنه الأب: color و time. (تم حذف كود المكوّن الأب لأنه يستخدم الحالة state، التي لا نريد أن نتعمق فيها الآن.)

جرب تغيير اللون في مربع الاختيار أدناه:

export default function Clock({ color, time }) {
  return (
    <h1 style={{ color: color }}>
      {time}
    </h1>
  );
}

يوضح هذا المثال أنه يمكن للمكوّن أن يتلقى خصائص مختلفة مع مرور الوقت. الخصائص ليست دائمًا ثابتة! هنا، تتغير الخاصية time كل ثانية، وتتغير الخاصية color عندما تختار لونًا آخر. تعكس الخصائص بيانات المكوّن في أي نقطة من الزمن، عوضاً عن البدايه فقط.

ومع ذلك، تكون الخصائص immutable—وهو مصطلح من علم الحوسبة يعني “لا يمكن تغييره”. عندما يحتاج المكوّن إلى تغيير خصائصه (على سبيل المثال، ردًا على تفاعل من المستخدم أو بيانات جديدة)، سيضطر إلى “طلب” من مكوّنه الأب تمريره خصائص مختلفة—كائن جديد! سيتم رفض الخصائص القديمة ثم سيستعيد محرك JavaScript في نهاية المطاف الذاكرة التي استهلكتها.

**لا تحاول “تغيير الخصائص”. ** عندما تحتاج إلى الاستجابة لإدخال المستخدم (مثل تغيير اللون المحدد)، ستحتاج إلى “تعيين الحالة”، والتي يمكنك التعرف عليها في الحالة: ذاكرة المكوّن.

Recap

  • لتمرير الخصائص، أضفها إلى JSX، تمامًا كما تفعل مع سمات HTML.
  • لقراءة الخصائص، استخدم function Avatar({ person, size }) صيغة تحليل.
  • يمكنك تحديد قيمة افتراضية مثل size = 100، التي تُستخدم في الخصائص الناقصة وغير المُعرّفة ‘undefined’.
  • يمكنك توجيه جميع الخصائص باستخدام صيغة الانتشار <Avatar {...props} />، ولكن لا تستخدمها بكثرة!
  • JSX المتداخل مثل <Card><Avatar /></Card> سيظهر كخاصية children للمكوّن Card.
  • تمثل الخصائص لقطات للقراءة فقط في الوقت: يتلقى كل عرض نسخة جديدة من الخصائص.
  • لا بمكنك تغيير الخصائص. عندما تحتاج إلى التفاعلية، ستحتاج إلى تعيين الحالة.

Challenge 1 of 3:
استخراج مكوّن

يحتوي مكوّن Gallery هذا على بعض الmarkup المماثلة جدًا لاثنين من الملفات. استخرِج مكوّن الProfile منه لتقليل التكرار. سوف تحتاج إلى اختيار الخصائص التي ستمررها إليه.

import { getImageUrl } from './utils.js';

export default function Gallery() {
  return (
    <div>
      <h1>العلماء البارزون</h1>
      <section className="profile">
        <h2>ماري سكاوندوڤسكا-كوري</h2>
        <img
          className="avatar"
          src={getImageUrl('szV5sdG')}
          alt="Maria Skłodowska-Curie"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>المهنة: </b> 
            عالمة فيزياء وكيمياء
          </li>
          <li>
            <b>الجوائز: 4 </b> 
            (جائزة نوبل في الفيزياء، جائزة نوبل في الكيمياء، ميدالية دافي، ميدالية ماتيوتشي)
          </li>
          <li>
            <b>اكتشفت: </b>
            البولونيوم (عنصر كيميائي)
          </li>
        </ul>
      </section>
      <section className="profile">
        <h2>كاتسوكو ساروهاشى</h2>
        <img
          className="avatar"
          src={getImageUrl('YfeOqp2')}
          alt="Katsuko Saruhashi"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>المهنة: </b> 
            جيوكيميائية
          </li>
          <li>
            <b>الجوائز: 2 </b> 
            (جائزة مياكي للجيوكيمياء، جائزة تاناكا)
          </li>
          <li>
            <b>اكتشفت: </b>
            طريقة لقياس ثاني أكسيد الكربون في المياه البحرية
          </li>
        </ul>
      </section>
    </div>
  );
}