اذهب إلى المحتوى

خاصيات مكونات React Component Properties) React)


عبد اللطيف ايمش

سنناقش في هذا الدرس استخدام خاصيات مكوِّنات React والتي تعرف بالخاصيات props.

ما هي خاصيات المكونات؟

أسهل طريقة لشرح خاصيات المكوِّنات هي القول أنَّها تسلك سلوك خاصيات HTML. بعبارةٍ أخرى، توفِّر الخاصيات خيارات الضبط للمكوِّن. فمثلًا، الشيفرة الآتية فيها المكوِّن Badge الذي يتوقع إرسال الخاصية name عند تهيئة المكوِّن:

class Badge extends React.Component {

  render() {

    return <div>{this.props.name}</div>;

  }

};

class BadgeList extends React.Component {

  render() {

    return (<div>

      <Badge name="Bill" />

      <Badge name="Tom" />

    </div>);

  }

};


ReactDOM.render(<BadgeList />, document.getElementById('app'));

داخل دالة التصيير للمكوِّن وعندما نستخدم المكوِّن ستُضاف الخاصية name إلى المكوِّن بنفس الطريقة التي نضيف فيها خاصية HTML إلى عنصر HTML (أي)؛ ثم ستستخدم الخاصية name من المكوِّن Badge (عبر this.props.name) كعقدة نصية للعقدة التي ستصيَّر عبر المكون Badge. هذا شبيهٌ بطريقة أخذ العنصر في HTML الخاصية value التي ستُستخدَم قيمتها لعرض نص داخل حقل الإدخال.

طريقة أخرى للتفكير في خاصيات المكوِّنات هي تخيلها كأنها قيم لخيارات الضبط المُرسَلة إلى المكوِّن. فإذا نظرتَ إلى نسخة لا تحتوي على صيغة JSX من المثال السابق فسيبدو لك جليًا أنَّ خاصيات المكوِّن ما هي إلا كائنٌ يُمرَّر إلى الخاصية createElement()‎ (أي React.createElement(Badge, { name: "Bill" })‎):

class Badge extends React.Component {

  render() {

    return React.createElement(

      "div",

      null, // null لم تُعرَّف خاصيات لذا ستكون القيمة 

      this.props.name // كقيمة نصية this.prop.name استخدام  

    );

  }

};




class BadgeList extends React.Component {

  render() {

    return React.createElement(

      "div",

      null,

      React.createElement(Badge, { name: "Bill" }),

      React.createElement(Badge, { name: "Tom" })

    );

  }

};


ReactDOM.render(React.createElement(BadgeList, null), document.getElementById('app'));

هذا شبيهٌ بطريقة ضبط الخاصيات مباشرةً على عقد React. لكن عند تمرير تعريف المكوِّن Badge إلى الدالة createElement()‎ بدلًا من قعدة، فستصبح الخاصيات props متاحةً على المكوِّن نفسه (أي this.props.name). تُمكِّننا خاصيات المكوِّنات من إعادة استخدام المكوِّن  مع أي اسم.

في الشيفرة التي ألقينا إليها نظرةً في هذا القسم، لاحظنا أنَّ المكوِّن BadgeList يستخدم مكونَي Badge مع كائن this.props خاصٌ بكلٍ واحدٍ منها. يمكننا التأكد من ذلك بعرض قيمة this.props عندما يُهيَّئ المكوِّن Badge:

class Badge extends React.Component {

  render() {

    return <div>{this.props.name}{console.log(this.props)}</div>;

  }

};


class BadgeList extends React.Component {

  render() {

    return (<div>

      <Badge name="Bill" />

      <Badge name="Tom" />

    </div>);

  }

};


ReactDOM.render(<BadgeList />, document.getElementById('app'));

نلاحظ أنَّ كل نسخة من مكوِّنات React تملك نسخةً خاصةً بها من خاصيةٍ اسمها props التي تكون كائن JavaScript فارغ، ثم سيُملَأ هذا الكائن عبر المكوِّن الأب باستخدام أي قيمة أو مرجعية في JavaScript، ثم ستُستخدَم هذه القيمة من المكوِّن أو تُمرَّر إلى المكونات الأبناء.

ملاحظات

  • في البيئات التي تستخدم ES5، لن نتمكن من تعديل الخاصية this.props لأنها كائنٌ مجمَّد (أي Object.isFrozen(this.props) === true;‎).
  • يمكنك أن تعدّ this.props على أنها كائنٌ للقراءة فقط.

إرسال الخاصيات props إلى مكوِّن

تُرسَل الخاصيات إلى المكوِّن عند إضافة قيم شبيهة بخاصيات HTML إلى المكوِّن عند استخدمه وليس عند تعريفه، فمثلًا، سنجد في الشيفرة الآتية أنَّ المكوِّن Badge قد عُرِّفَ أولًا، ثم أرسلنا خاصيةً له وهي name="Bill"‎ أثناء استخدامه (أي عند تصيير ``):

class Badge extends React.Component {

  render() {

    return <div>{this.props.name}</div>;

  }

};


ReactDOM.render(<Badge name="Bill" />, document.getElementById('app'));

أبقِ في ذهنك أنَّ بإمكاننا إرسال خاصية إلى المكوِّن في أي مكان يمكن أن يُستخدَم المكوِّن فيه. فعلى سبيل المثال، يبيّن المثال من القسم السابقة استخدام المكوِّن Badge والخاصية name ضمن المكوِّن BadgeList:

class Badge extends React.Component {

  render() {

    return <div>{this.props.name}</div>;

  }

};


class BadgeList extends React.Component {

  render() {

    return (<div>

      <Badge name="Bill" />

      <Badge name="Tom" />

    </div>

    );

  }

};


ReactDOM.render(<BadgeList />, document.getElementById('app'));

ملاحظات

  • يجب أن تُعدّ خاصيات المكوِّن غيرُ قابلةٍ للتعديل، ويمكن عدم تعديل الخاصيات المُرسَلة من مكوِّن آخر. فلو احتجتَ إلى تعديل قيمة خاصيات أحد المكوِّنات ثم إعادة تصييره، فلا تضبط الخاصيات باستخدام this.props.[PROP] = [NEW PROP].

الحصول على خاصيات المكوِّن

كما ناقشنا في الدرس السابق، يمكن الوصول إلى إلى نسخة المكوِّن من أيٍّ من خيارات الضبط التي تستعمل دالةً عبر الكلمة المحجوزة this. ففي المثال الآتي استخدمنا الكلمة المحجوزة this للوصول إلى خاصيات props المكوِّن Badge من خيار الضبط render بكتابة this.props.name:

class Badge extends React.Component {

  render() {

    return <div>{this.props.name}</div>;

  }

};


ReactDOM.render(<Badge name="Bill" />, document.getElementById('app'));

ليس من الصعب معرفة ما يحدث إذا ألقينا نظرةً على شيفرة JavaScript المحوَّلة من JSX:

class Badge extends React.Component {

  render() {

    return React.createElement(

      "div",

      null,

      this.props.name

    );

  }

};


ReactDOM.render(React.createElement(Badge, { name: "Bill" }), document.getElementById('app'));

أُرسِل الكائن { name: "Bill"‎ } إلى الدالة createElement()‎ إضافةً إلى مرجعيةٍ إلى المكوِّن Badge. القيمة { name: "Bill"‎ } ستُضبَط كخاصية للمكوِّن قابلةٌ للوصول من الكائن props، أي أنَّ this.props.name === "Bill"‎.

ملاحظات

  • تذكَّر أنَّ this.props للقراءة فقط، ولا يجوز ضبط الخاصيات باستخدام this.props.PROP = 'foo'‎.

ضبط قيم افتراضية لخاصيات المكوِّن

يمكن ضبط الخاصيات الافتراضية عند تعريف المكوِّن باستخدام خيار الضبط getDefaultProps.

المثال الآتي يبيّن كيف عرَّفنا خيار ضبط افتراضي للمكوِّن Badge للخاصية name:

class Badge extends React.Component {

  static defaultProps = {

    name:'John Doe'

  }

  render() {

    return <div>{this.props.name}</div>;

  }

};


class BadgeList extends React.Component {

  render() {

    return (<div>

      <Badge />

      <Badge name="Tom Willy" />

    </div>);

  }

};


ReactDOM.render(<BadgeList />, document.getElementById('app'));

ستُضبَط الخاصيات الافتراضية على الكائن this.props إذا لم تُرسَل خاصيات إلى المكوِّن. يمكنك التحقق من ذلك بملاحظة أنَّ المكوِّن Badge الذي لم تُضبَط الخاصية name فيه ستأخذ القيمة الافتراضية 'John Doe'.

خاصيات المكونات هي أكثر من مجرد سلاسل نصية

قبل أن نلقي نظرةً على التحقق من الخاصيات، علينا أن نستوعب أولًا أنَّ خاصيات المكونات يمكن أن تكون أي قيمة صالحة في JavaScript.

في المثال أدناه، سنضبط عدِّة خاصيات افتراضية تحتوي على مختلف قيم JavaScript:

class MyComponent extends React.Component {

  static defaultProps = {

      propArray: [],

      propBool: false,

      propFunc: function(){},

      propNumber: 5,

      propObject: {},

      propString: 'string'

  }

  render() {

    return (<div>

      propArray: {this.props.propArray.toString()} 

      <br /><br />

      propFunc returns: {this.props.propFunc()} 

    </div>) ;

  }

};




ReactDOM.render(<MyComponent propArray={[1,2,3]} propFunc={function(){return 2;}} />, document.getElementById('app'));

لاحظ كيف أعيدت الكتابة على الخاصيتين propArray و propObject مع قيم جديدة عند إنشاء نسخة من المكوِّن MyComponent.

الفكرة الرئيسية من هذا القسم هو توضيح أنَّنا لسنا محدودين بالقيم النصية عند تمرير قيم للخاصيات.

التحقق من خاصيات المكوِّنات

لاستخدامٍ سليمٍ للخاصيات ضمن المكوِّنات، يجب أن نتحقق من قيمتها عند إنشاء نسخ المكوِّنات.

عند تعريف خيار الضبط propTypes يمكننا أن نضبط كيف يجب أن تكون الخاصيات وكيف نتحقق منها. سنتحقق في المثال أدناه لنرى إن كانت الخاصيتان propArray و propObject من نوع البيانات الصحيح وسنرسلها إلى المكوِّن عند تهيئته:

import PropTypes from 'prop-types';

class MyComponent extends React.Component {

  static propTypes = {

    propArray: PropTypes.array.isRequired,

    propFunc: PropTypes.func.isRequired,

  }




  render() {

    return (<div>

      propArray: {this.props.propArray.toString()} 

      <br /><br />

      propFunc returns: {this.props.propFunc()} 

    </div>);

  }

};

// لهذا المكوِّن خاصياتٌ خطأ

ReactDOM.render(<MyComponent propArray={{test:'test'}} />, document.getElementById('app'));




// لهذا المكوِّن خاصياتٌ صحيحة

// ReactDOM.render(<MyComponent propArray={[1,2]} propFunc={function(){return 3;}} />, document.getElementById('app'));

لم نرسل الخاصيات الصحيحة المُحدَّدة عبر propTypes لتوضيح أنَّ فعل ذلك سيؤدي إلى حدوث خطأ. ستؤدي الشيفرة السابقة إلى ظهور رسالة الخطأ الآتية:

Warning: Failed propType: Invalid prop `propArray` of type `object` supplied to `MyComponent`, expected `array`

Warning: Failed propType: Required prop `propFunc` was not specified in `MyComponent`.

Uncaught TypeError: this.props.propFunc is not a function

توفِّر React عددًا من المتحققات الداخلية (مثل PropTypes[VALIDATOR]) والتي سأشرحها بإيجاز فيما يلي، إضافةً إلى إمكانية إنشاء متحققات مخصصة.

(انتقلت إلى مكتبة مختلفة*)

المتحققات الأساسية من الأنواع

React.PropTypes.string إذا اُستخدِمَت خاصيةٌ، فتحقق أنها سلسلة نصية
React.PropTypes.bool إذا اُستخدِمَت خاصيةٌ، فتحقق أنها قيمة منطقية
React.PropTypes.func إذا اُستخدِمَت خاصيةٌ، فتحقق أنها دالة
React.PropTypes.number إذا اُستخدِمَت خاصيةٌ، فتحقق أنها عدد
React.PropTypes.object إذا اُستخدِمَت خاصيةٌ، فتحقق أنها كائن
React.PropTypes.array إذا اُستخدِمَت خاصيةٌ، فتحقق أنها مصفوفة
React.PropTypes.any إذا اُستخدِمَت خاصيةٌ، فتحقق أنها من أي نوع من الأنواع

متحققات القيم المطلوبة

React.PropTypes.[TYPE].isRequired إضافة ‎.isRequired إلى أي نوع من المتحققات سيؤدي إلى جعل الخاصية مطلوبةً (مثال ذلك propTypes:{propFunc:React.PropTypes.func.isRequired})

متحققات العناصر

React.PropTypes.element الخاصية هي عنصر React.
React.PropTypes.node أي شيء يمكن تصييره: الأرقام، أو السلاسل النصية، أو العناصر، أو مصفوفة تحتوي هذه الأنواع

المتحققات المتعددة

React.PropTypes.oneOf(['Mon','Fri'])‎ الخاصية هي أحد أنواع القيم المُحدَّدة
React.PropTypes.oneOfType([React.PropTypes.string,React.PropTypes.number])‎ الخاصية هي كائن يمكن أن يكون أحد أنواع القيم المُحدَّدة

متحققات المصفوفات والكائنات

React.PropTypes.arrayOf(React.PropTypes.number)‎ الخاصية هي مصفوفة تحتوي على نوع واحد من القيم
React.PropTypes.objectOf(React.PropTypes.number)‎ هي كائن يحتوي على أحد أنواع القيم
React.PropTypes.instanceOf(People)‎ هي كائن يكون نسخةً من دالةٍ بانية معينة (كما في الكلمة المحجوزة instanceof)
React.PropTypes.shape({color:React.PropTypes.string,size: React.PropTypes.number})‎ هي كائن يحتوي على خاصيات من أنواعٍ معينة

المتحققات المخصصة

function(props, propName, componentName){}‎

توفير دالة خاصة بك للتحقق

ترجمة -وبتصرف- للفصل React Component Properties من كتاب React Enlightenment


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...