الفرق بين المراجعتين لصفحة: «React/faq state»
Kinan-mawed (نقاش | مساهمات) أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE:حالة المكونات}}</noinclude>' |
Kinan-mawed (نقاش | مساهمات) لا ملخص تعديل |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:حالة المكونات}}</noinclude> | <noinclude>{{DISPLAYTITLE:حالة المكونات}}</noinclude> | ||
== ماذا يفعل التابع setState؟ == | |||
يُجدوِل التابع <code>setState()</code> تحديثًا لكائن حالة المكوّن <code>state</code>. عندما تتغير الحالة يستجب المكوّن بإعادة التصيير. | |||
== ما الفرق بين الحالة <code>state</code> والخاصيّات <code>props</code>؟ == | |||
الخاصيّات <code>props</code> (اختصارًا للكلمة properties) والحالة <code>state</code> كلاهما عبارة عن كائنات JavaScript مجرّدة. وفي حين أنّ كلاهما يحمل معلومات تؤثر في ناتج التصيير، فهما مختلفان بطريقة واحدة هامة، حيث تُمرَّر الخاصيّات إلى المكوّن (بشكل مماثل لمُعاملات الدالة) بينما تُدار الحالة <code>state</code> ضمن المكوّن (بشكل مشابه للمتغيرات المعرفة بداخل الدالة). | |||
هنا تجد مصادر جيدة لقراءة المزيد حول استخدام الخاصيّات والحالة: | |||
* Props vs State. | |||
* ReactJS: Props vs. State. | |||
== لماذا يُعطيني التابع <code>setState</code> القيمة الخاطئة؟ == | |||
في React تُمثل <code>this.props</code> و <code>this.state</code> القيم المُصيَّرة، أي المعروضة على الشاشة حاليًّا. | |||
تكون استدعاءات التابع <code>setState</code> غير متزامنة، فلا تعتمد على <code>this.state</code> لتعكس القيمة الجديدة للحالة بشكل مباشر بعد استدعاء التابع <code>setState</code>. مرر دالة تحديث بدلًا من تمرير كائن إن احتجت لحساب القيم بناءً على الحالة الحاليّة (انظر في الأسفل للمزيد من التفاصيل). | |||
مثال عن شيفرة لن تعمل كما هو متوقع:<syntaxhighlight lang="javascript"> | |||
incrementCount() { | |||
// ملاحظة: لن يعمل هذا كما هو متوقع | |||
this.setState({count: this.state.count + 1}); | |||
} | |||
handleSomething() { | |||
// فلنقل أنّ this.state.count تبدأ بالقيمة 0 | |||
this.incrementCount(); | |||
this.incrementCount(); | |||
this.incrementCount(); | |||
// عندما تعيد React تصيير المكون فستصبح قيمة this.state.count 1 | |||
// ولكنك كنت تتوقعها أنها 3 | |||
// هذا لأنّ الدالة incrementCount() | |||
// تقرأ this.state.count | |||
// ولكن لا تحدث React قيمتها حتى إعادة تصيير المكون | |||
// لذا ستقرأ React قيمة هذه الدالة على أنها صفر في كل مرة وستعينها للقيمة واحد | |||
// الحل موصوف لاحقًا | |||
} | |||
</syntaxhighlight>انظر في الأسفل لمعرفة كيفية إصلاح هذه المشكلة. | |||
== كيف أحدث الحالة بقيم تعتمد على الحالة الحالية؟ == | |||
مرر دالة بدلًا من كائن إلى التابع <code>setState</code> لضمان استخدام الاستدعاء دائمًا لآخر إصدار من الحالة. | |||
== ما الفرق بين تمرير كائن أو دالة إلى التابع <code>setState</code>؟ == | |||
يسمح لك تمرير دالة التحديث بالوصول إلى قيمة الحالة الحالية بداخل دالة التحديث. وبما أنّ استدعاءات التابع <code>setState</code> مجدولة سيسمح لك ذلك بسلسلة التحديثات وضمان أنّها تبني فوق بعضها بدلًا من التعارض فيما بينها:<syntaxhighlight lang="javascript"> | |||
incrementCount() { | |||
this.setState((prevState) => { | |||
// هام: اقرأ قيمة prevState بدلًا من this.state عند التحديث | |||
return {count: prevState.count + 1} | |||
}); | |||
} | |||
handleSomething() { | |||
// فلنفترض أنّ قيمة this.state.count تبدأ من الصفر | |||
this.incrementCount(); | |||
this.incrementCount(); | |||
this.incrementCount(); | |||
// إن قرأت قيمة this.state.count الآن فستكون لا زالت صفر | |||
// ولكن عندما يعاد تصيير المكون فستصبح 3 | |||
} | |||
</syntaxhighlight>تعلم المزيد حول <code>setState</code>. | |||
== متى يكون التابع <code>setState</code> غير متزامن؟ == | |||
حاليًّا التابع <code>setState</code> غير متزامن بداخل معالج الأحداث. | |||
إن كان المكوّن الأب <code>Parent</code> والمكوّن الابن <code>Child</code> يستدعيان التابع <code>setState</code> خلال حدث النقر يضمن لنا عدم التزامن ألّا يُعاد تصيير المكوّن الابن <code>Child</code> مرتين، وبدلًا من ذلك تمسح React تحديثات الحالة في نهاية أحداث المتصفّح. ينتج عن هذا تحسين هام في الأداء في التطبيقات الكبيرة. | |||
لا يزال هذا تفصيلًا تنفيذيًّا لذا تجنّب الاعتماد عليه بشكل مباشر. في الإصدارات القادمة ستطبّق React التحديثات بشكل افتراضي في حالات أكثر. | |||
== لماذا لا تُحدِّث React قيمة <code>this.state</code> بشكلٍ متزامن؟ == | |||
كما تحدثنا في القسم السابق، تنتظر React عن قصد حتى تستدعي جميع المكوّنات التابع <code>setState()</code> في مُعالِجات أحداثها قبل البدء بإعادة التصيير. يُسرِّع هذا الأداء عن طريق تجنّب إعادة التصيير غير الضروريّة. | |||
على أيّة حال قد لا تزال تتساءل لماذا لا تُحدِّث React قيمة <code>this.state</code> بشكل مباشر وبدون إعادة التصيير. | |||
هنالك سببان رئيسيّان: | |||
* يخرق هذا التوافقيّة بين الخاصيّات <code>props</code> والحالة <code>state</code>، مسببًا مشاكل من الصعب تنقيحها. | |||
* سيجعل هذا من بعض الميّزات التي نعمل عليها مستحيلة التطبيق. | |||
يشرح هذا التعليق في GitHub بالتفصيل أمثلة عن هذا. | |||
== هل ينبغي أن أستخدم مكتبات إدارة الحالة مثل Redux أو MobX؟ == | |||
ربّما. | |||
من الأفضل في البداية التعرّف على React أولًا قبل إضافة مكتبات أخرى. بإمكانك بناء تطبيقات معقدة وكبيرة باستخدام React فقط. | |||
==مصادر== | |||
*[https://reactjs.org/docs/faq-state.html صفحة حالة المكونات في توثيق React الرسمي]. | |||
[[تصنيف:React]] |
مراجعة 09:53، 12 سبتمبر 2018
ماذا يفعل التابع setState؟
يُجدوِل التابع setState()
تحديثًا لكائن حالة المكوّن state
. عندما تتغير الحالة يستجب المكوّن بإعادة التصيير.
ما الفرق بين الحالة state
والخاصيّات props
؟
الخاصيّات props
(اختصارًا للكلمة properties) والحالة state
كلاهما عبارة عن كائنات JavaScript مجرّدة. وفي حين أنّ كلاهما يحمل معلومات تؤثر في ناتج التصيير، فهما مختلفان بطريقة واحدة هامة، حيث تُمرَّر الخاصيّات إلى المكوّن (بشكل مماثل لمُعاملات الدالة) بينما تُدار الحالة state
ضمن المكوّن (بشكل مشابه للمتغيرات المعرفة بداخل الدالة).
هنا تجد مصادر جيدة لقراءة المزيد حول استخدام الخاصيّات والحالة:
- Props vs State.
- ReactJS: Props vs. State.
لماذا يُعطيني التابع setState
القيمة الخاطئة؟
في React تُمثل this.props
و this.state
القيم المُصيَّرة، أي المعروضة على الشاشة حاليًّا.
تكون استدعاءات التابع setState
غير متزامنة، فلا تعتمد على this.state
لتعكس القيمة الجديدة للحالة بشكل مباشر بعد استدعاء التابع setState
. مرر دالة تحديث بدلًا من تمرير كائن إن احتجت لحساب القيم بناءً على الحالة الحاليّة (انظر في الأسفل للمزيد من التفاصيل).
مثال عن شيفرة لن تعمل كما هو متوقع:
incrementCount() {
// ملاحظة: لن يعمل هذا كما هو متوقع
this.setState({count: this.state.count + 1});
}
handleSomething() {
// فلنقل أنّ this.state.count تبدأ بالقيمة 0
this.incrementCount();
this.incrementCount();
this.incrementCount();
// عندما تعيد React تصيير المكون فستصبح قيمة this.state.count 1
// ولكنك كنت تتوقعها أنها 3
// هذا لأنّ الدالة incrementCount()
// تقرأ this.state.count
// ولكن لا تحدث React قيمتها حتى إعادة تصيير المكون
// لذا ستقرأ React قيمة هذه الدالة على أنها صفر في كل مرة وستعينها للقيمة واحد
// الحل موصوف لاحقًا
}
انظر في الأسفل لمعرفة كيفية إصلاح هذه المشكلة.
كيف أحدث الحالة بقيم تعتمد على الحالة الحالية؟
مرر دالة بدلًا من كائن إلى التابع setState
لضمان استخدام الاستدعاء دائمًا لآخر إصدار من الحالة.
ما الفرق بين تمرير كائن أو دالة إلى التابع setState
؟
يسمح لك تمرير دالة التحديث بالوصول إلى قيمة الحالة الحالية بداخل دالة التحديث. وبما أنّ استدعاءات التابع setState
مجدولة سيسمح لك ذلك بسلسلة التحديثات وضمان أنّها تبني فوق بعضها بدلًا من التعارض فيما بينها:
incrementCount() {
this.setState((prevState) => {
// هام: اقرأ قيمة prevState بدلًا من this.state عند التحديث
return {count: prevState.count + 1}
});
}
handleSomething() {
// فلنفترض أنّ قيمة this.state.count تبدأ من الصفر
this.incrementCount();
this.incrementCount();
this.incrementCount();
// إن قرأت قيمة this.state.count الآن فستكون لا زالت صفر
// ولكن عندما يعاد تصيير المكون فستصبح 3
}
تعلم المزيد حول setState
.
متى يكون التابع setState
غير متزامن؟
حاليًّا التابع setState
غير متزامن بداخل معالج الأحداث.
إن كان المكوّن الأب Parent
والمكوّن الابن Child
يستدعيان التابع setState
خلال حدث النقر يضمن لنا عدم التزامن ألّا يُعاد تصيير المكوّن الابن Child
مرتين، وبدلًا من ذلك تمسح React تحديثات الحالة في نهاية أحداث المتصفّح. ينتج عن هذا تحسين هام في الأداء في التطبيقات الكبيرة.
لا يزال هذا تفصيلًا تنفيذيًّا لذا تجنّب الاعتماد عليه بشكل مباشر. في الإصدارات القادمة ستطبّق React التحديثات بشكل افتراضي في حالات أكثر.
لماذا لا تُحدِّث React قيمة this.state
بشكلٍ متزامن؟
كما تحدثنا في القسم السابق، تنتظر React عن قصد حتى تستدعي جميع المكوّنات التابع setState()
في مُعالِجات أحداثها قبل البدء بإعادة التصيير. يُسرِّع هذا الأداء عن طريق تجنّب إعادة التصيير غير الضروريّة.
على أيّة حال قد لا تزال تتساءل لماذا لا تُحدِّث React قيمة this.state
بشكل مباشر وبدون إعادة التصيير.
هنالك سببان رئيسيّان:
- يخرق هذا التوافقيّة بين الخاصيّات
props
والحالةstate
، مسببًا مشاكل من الصعب تنقيحها. - سيجعل هذا من بعض الميّزات التي نعمل عليها مستحيلة التطبيق.
يشرح هذا التعليق في GitHub بالتفصيل أمثلة عن هذا.
هل ينبغي أن أستخدم مكتبات إدارة الحالة مثل Redux أو MobX؟
ربّما.
من الأفضل في البداية التعرّف على React أولًا قبل إضافة مكتبات أخرى. بإمكانك بناء تطبيقات معقدة وكبيرة باستخدام React فقط.