سنناقش في هذا الدرس حالة المكوِّنات (component state).
ما هي حالة المكون (Component State)؟
أغلبية المكونات تأخذ الخاصيات props
وتصيّر العنصر، لكن تتيح المكونات الحالة أيضًا، والتي يمكن أن تستخدم لتخزين معلومات حول المكوِّن التي يمكن أن تتغير مع مرور الوقت. وعادةً يأتي التغيير نتيجةً لأحداث المستخدم أو أحداث النظام (مثل رد لمدخلات المستخدم، أو طلبية للخادم بعد مرور فترة زمنية معيّنة).
بعض الأمور التي يجب أخذها بالحسبان حول حالة مكوِّنات React:
-
إذا كان للمكوِّن حالة فيمكن ضبط الحالة الافتراضية
this.setState()
في الدالة البانية. - تغيرات الحالة هي ما تجعلنا نعيد تصيير المكوِّن وجميع المكونات الفرعية التابعة له.
-
يمكنك إعلام المكوِّن بتغيّر الحالة باستخدام
this.setState()
لضبط حالةٍ جديدة. -
يمكن أن تدمج تغيرات الحالة البيانات الجديدة مع البيانات القديمة التي ما تزال محتواةً في الحالة (أي
this.state
). -
عند تغيير الحالة، فستجري عملية إعادة التصيير داخليًا، ولا يفترض بك استدعاء
this.render()
مباشرةً أبدًا. -
يجب أن يحتوي كائن الحالة على القدر الأدنى من البيانات اللازم لواجهة المستخدم؛ فلا تضع البيانات المحسوبة أو مكونات React الأخرى أو الخاصيات
props
في كائن الحالة.
العمل مع حالة المكونات
يتطلب التعامل مع حالة المكونات عادةً ضبط الحالة الافتراضية، والوصول إلى الحالة الحالية، وتحديث الحالة.
سننشِئ في المثال الآتي المكوِّن الذي يبيّن استخدام
this.state.[STATE] و
this.setState(). إذا ضغطتَ على المكوِّن في متصفح الويب (أي الوجه المبتسم) فستجد أنَّ المكوِّن سيبدِّل بين الحالات المتاحة (أي الأوجه المبتسمة)، وبالتالي تكون هنالك ثلاثة حالات ممكنة للمكوِّن وهي مرتبطة بالواجهة الرسومية ومعتمدة على نقرات المستخدم في واجهة المستخدم:
class MoodComponent extends React.Component { state = {mood: ':|'}; constructor(props){ super(props); this.changeMood = this.changeMood.bind(this) } changeMood(event,a){ const moods = [':)',':|',':(']; const current = moods.indexOf(event.target.textContent); this.setState({mood: current === 2 ? moods[0] : moods[current+1]}); } render() { return ( <span style={{fontSize:'60',border:'1px solid #333',cursor:'pointer'}} onClick={this.changeMood}> {this.state.mood} </span> ) } }; ReactDOM.render(< MoodComponent />, app);
لاحظ أنَّ للمكوِّن حالةً افتراضيةً هي :|، وهي مضبوطة باستخدام state = {mood: ':|'};
وهي تستخدم في المكوِّن عند تصييره لأول مرة عبر
{this.state.mood}.
أضفنا مستمعًا للأحداث لتغيير الحالة، وهي هذه الحالة سيؤدي حدث النقر (onClick
) على عقدة إلى استدعاء الدالة
changeMood، وداخل هذه الدالة سنستخدم
this.setState() للتبديل إلى الحالة التالية اعتمادًا على قيمة الحالة الحالية. بعد إجراء هذا التحديث (لاحظ أنَّ
setState() ستدمج التعديلات) فسيعاد تصيير العنصر وستتغير واجهة المستخدم.
بعض الأمور التي علينا إبقاؤها في ذهننا عند الحديث عن حالة مكوِّنات React:
-
إذا كان للمكوِّن حالة فيمكن ضبط الحالة الافتراضية الخاصية
state
. - تغيرات الحالة هي ما تجعلنا نعيد تصيير المكوِّن وجميع المكونات الفرعية التابعة له.
-
يمكنك إعلام المكوِّن بتغيّر الحالة باستخدام
this.setState()
لضبط حالةٍ جديدة. هنالك طرائق أخرى (مثلforceUpdate()
) ولكن لا يجدر بناء استخدامها إلا إذا أردنا دمج React مع مكتباتٍ من طرف ثالث. -
يمكن أن تدمج تغيرات الحالة البيانات الجديدة مع البيانات القديمة التي ما تزال محتواةً في الحالة (أي
this.state
). لكن هذا دمجٌ أو تحديثٌ سطحي، فلن يجرى عملية دمج عميقة. -
عند تغيير الحالة، فستجري عملية إعادة التصيير داخليًا، ولا يفترض بك استدعاء
this.render()
مباشرةً أبدًا. -
يجب أن يحتوي كائن الحالة على القدر الأدنى من البيانات اللازم لواجهة المستخدم؛ فلا تضع البيانات المحسوبة أو مكونات React الأخرى أو الخاصيات
props
في كائن الحالة.
الفروقات بين الحالة والخاصيات props
هنالك أرضيةٌ مشتركة بين الحالة state
والخاصيات props
:
- كلاهما كائنات JavaScript عادية.
- يمكن لكليهما أن يمتلك قيمًا افتراضية.
-
يمكن الوصول إليها باستخدام
this.props
أوthis.state
، لكن لا يجوز أن نضبط قيمهما بهذه الطريقة، إذ سيكون كلاهما للقراءة فقط عند استخدامthis
.
لكنهما يستخدمان لأغراضٍ مختلفة وبطرائق مختلفة.
الخاصيات props
:
- تُمرَّر الخاصيات إلى المكوِّنات من البنية الأعلى منها، سواءً كانت من مكوِّنٍ أب أو بداية المجال حيث صُيَّرت React من الأساس.
- الغرض من الخاصيات هو تمرير قيم الضبط إلى المكوِّن. تخيل أنها كالوسائط المُمرَّرة إلى دالة (وإن لم تكن تستعمل صيغة JSX فهذا ما تفعله تحديدًا).
- الخاصيات غير قابلة للتعديل في المكوِّن الذي يستقبلها، أي لا يمكننا تعديل الخاصيات المُمرَّرة إلى المكوِّن من داخل المكوِّن نفسه.
الحالة (state):
- الحالة هي تمثيلٌ للبيانات الذي سيرتبط في مرحلةٍ ما مع الواجهة الرسومية.
-
يجب أن تبدأ الحالة دومًا بقيمةٍ افتراضية، ثم ستُعدّل الحالة داخليًا في المكوِّن باستخدام
setState()
. - يمكن تعديل الحالة باستخدام المكوِّن الذي يحتوي عليها فقط، أي أنها خاصة.
- لا يفترض تعديل حالة المكوِّنات الأبناء، ويجب ألا يشارك المكوِّن حالةً قابلةً للتعديل.
-
يجب أن يحتوي كائن الحالة على القدر الأدنى من البيانات اللازم لواجهة المستخدم؛ فلا تضع البيانات المحسوبة أو مكونات React الأخرى أو الخاصيات
props
في كائن الحالة.
إنشاء مكونات عديمة الحالة (Stateless Components)
عندما يكون المكون نتيجةً لاستخدام الخاصيات props
فقط دون وجود حالة state
، فيمكن كتابة المكوِّن على شكل دالة صرفة مما يجعلنا نتفادى إنشاء نسخة من مكوِّن React. ففي المثال الآتي سيكون MyComponent
نتيجةً لاستدعاء دالة ناتجة عن React.createElement()
.
var MyComponent = function(props){ return <div>Hello {props.name}</div>; }; ReactDOM.render(<MyComponent name="doug" />, app);
إذا ألقينا نظرةً على شيفرة JavaScript الناتجة عن عملية تحويل JSX، فستبدو الأمور جليةً وواضحةً لنا:
var MyComponent = function MyComponent(props) { return React.createElement( "div", null, "Hello ", props.name ); }; ReactDOM.render(React.createElement(MyComponent, { name: "doug" }), app);
إنشاء مكوِّن React دون اشتقاق الصنف React.Component
يشار إليه عادةً بمكوِّن عديم الحالة.
لا يمكن تمرير خيارات الضبط إلى المكونات عديمة الحالة (مثل render
أو componentWillUnmount
…إلخ.)؛ لكن يمكن ضبط .propTypes
و .defaultProps
على الدالة.
الشيفرة الآتية توضِّح مكوِّنًا عديم الحالة يستخدم .propTypes
و .defaultProps
:
import PropTypes from 'prop-types'; var MyComponent = function(props){ return <div>Hello {props.name}</div>; }; MyComponent.defaultProps = {name:"John Doe"}; MyComponent.propTyes = {name: PropTypes.string}; ReactDOM.render(<MyComponent />, app);
ملاحظات
- حاول أن تجعل أكبر عدد من المكونات عديمَ الحالة.
ترجمة -وبتصرف- للفصل React Component State من كتاب React Enlightenment
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.