State: ذاكرة المكون
غالبًا ما تحتاج المكونات إلى تغيير ما يظهر على الشاشة نتيجة للتفاعل. الكتابة في النموذج يجب أن تحدّث حقل الإدخال، والنقر على “التالي” في عرض الصور المتتابع يجب أن يغير الصورة المعروضة، والنقر على “شراء” يجب أن يضع المنتج في سلة التسوق. تحتاج المكونات إلى “تذكر” الأشياء: قيمة الإدخال الحالية، الصورة الحالية، سلة التسوق. في React، هذا النوع من ذاكرة المكون المحددة يسمى state (حالة).
You will learn
- كيفية إضافة متغير حالة باستخدام
useStateHook - ما هو الزوج من القيم الذي يعيده
useStateHook - كيفية إضافة أكثر من متغير حالة واحد
- لماذا تسمى الحالة محلية
عندما لا يكون المتغير العادي كافيا
إليك مكونا يعرض صورة منحوتة. النقر على زر “Next” يجب أن يعرض المنحوتة التالية عن طريق تغيير index إلى 1 ثم 2 وهكذا. ومع ذلك هذا لن ينجح (يمكنك تجربته!):
معالج الحدث handleClick يحدّث متغيرًا محليًا، index. لكن شيئين يمنعان هذا التغيير من أن يكون مرئيًا:
- المتغيرات المحلية لا تستمر بين عمليات التصيير. عندما يصيّر React هذا المكون للمرة الثانية، يصيّره من الصفر — لا يأخذ في الاعتبار أي تغييرات على المتغيرات المحلية.
- التغييرات على المتغيرات المحلية لن تؤدي إلى تشغيل عمليات التصيير. React لا يدرك أنه بحاجة إلى تصيير المكون مرة أخرى مع البيانات الجديدة.
لتحديث مكون ببيانات جديدة، يجب أن يحدث شيئان:
- الاحتفاظ بالبيانات بين عمليات التصيير.
- تشغيل React لتصيير المكون بالبيانات الجديدة (إعادة التصيير).
الـ useState Hook يوفر هذين الشيئين:
- متغير حالة للاحتفاظ بالبيانات بين عمليات التصيير.
- دالة محدّث الحالة لتحديث المتغير وتشغيل React لتصيير المكون مرة أخرى.
إضافة متغير حالة
لإضافة متغير حالة، استورد useState من React في أعلى الملف:
import { useState } from 'react';
ثم، استبدل هذا السطر:
let index = 0;
بـ
const [index, setIndex] = useState(0);
index هو متغير حالة و setIndex هي دالة المُحدّث.
بناء
[و]هنا يسمى array destructuring ويتيح لك قراءة القيم من array. الـ array الذي يرجعهuseStateيحتوي دائمًا على عنصرين بالضبط.
هذه هي كيفية عملهما معًا في handleClick:
function handleClick() { setIndex(index + 1); }
الآن النقر على زر “Next” يبدّل المنحوتة الحالية:
Meet your first Hook
In React, useState, as well as any other function starting with “use”, is called a Hook.
Hooks are special functions that are only available while React is rendering (which we’ll get into in more detail on the next page). They let you “hook into” different React features.
State is just one of those features, but you will meet the other Hooks later.
Anatomy of useState
When you call useState, you are telling React that you want this component to remember something:
const [index, setIndex] = useState(0);
In this case, you want React to remember index.
The only argument to useState is the initial value of your state variable. In this example, the index’s initial value is set to 0 with useState(0).
Every time your component renders, useState gives you an array containing two values:
- The state variable (
index) with the value you stored. - The state setter function (
setIndex) which can update the state variable and trigger React to render the component again.
Here’s how that happens in action:
const [index, setIndex] = useState(0);
- Your component renders the first time. Because you passed
0touseStateas the initial value forindex, it will return[0, setIndex]. React remembers0is the latest state value. - You update the state. When a user clicks the button, it calls
setIndex(index + 1).indexis0, so it’ssetIndex(1). This tells React to rememberindexis1now and triggers another render. - Your component’s second render. React still sees
useState(0), but because React remembers that you setindexto1, it returns[1, setIndex]instead. - وهكذا!
إعطاء مكون متغيرات حالة متعددة
يمكنك الحصول على أي عدد من متغيرات الحالة من أي نوع تريده في مكون واحد. هذا المكون لديه متغيرا حالة، رقم index و boolean showMore الذي يتم تبديله عند النقر على “Show details”:
من الجيد أن يكون لديك متغيرات حالة متعددة إذا كانت حالتها غير مرتبطة، مثل index و showMore في هذا المثال. ولكن إذا وجدت أنك غالبًا تغيّر متغيري حالة معًا، فقد يكون من الأسهل دمجهما في واحد. على سبيل المثال، إذا كان لديك نموذج به العديد من الحقول، فمن الأفضل أن يكون لديك متغير حالة واحد يحتوي على كائن بدلاً من متغير حالة لكل حقل. اقرأ اختيار بنية الحالة للمزيد من النصائح.
غوص عميق
ربما لاحظت أن استدعاء useState لا يتلقى أي معلومات حول أي متغير حالة يشير إليه. لا يوجد “معرّف” يتم تمريره إلى useState، فكيف يعرف أي من متغيرات الحالة يجب إرجاعه؟ هل يعتمد على بعض السحر مثل تحليل دوالك؟ الجواب لا.
بدلاً من ذلك، لتمكين بنيتهم الموجزة، تعتمد الـ Hooks على ترتيب استدعاء مستقر في كل عرض لنفس المكوّن. هذا يعمل بشكل جيد في الممارسة لأنه إذا اتبعت القاعدة أعلاه (“استدع الـ Hooks فقط في المستوى الأعلى”)، سيتم استدعاء الـ Hooks دائمًا بنفس الترتيب. بالإضافة إلى ذلك، إضافة linter تلتقط معظم الأخطاء.
داخليًا، يحتفظ React بمصفوفة من أزواج الحالة لكل مكوّن. كما يحتفظ بفهرس الزوج الحالي، والذي يتم تعيينه إلى 0 قبل العرض. في كل مرة تستدعي فيها useState، يعطيك React زوج الحالة التالي ويزيد الفهرس. يمكنك قراءة المزيد عن هذه الآلية في React Hooks: Not Magic, Just Arrays.
هذا المثال لا يستخدم React لكنه يعطيك فكرة عن كيفية عمل useState داخليًا:
ليس عليك فهم هذا لاستخدام React، لكن قد تجد هذا نموذجًا ذهنيًا مفيدًا.
الحالة معزولة وخاصة
الحالة محلية لنسخة المكون على الشاشة. بمعنى آخر، إذا صيّرت نفس المكون مرتين، فإن كل نسخة ستكون لديها حالة معزولة تمامًا! تغيير واحدة منها لن يؤثر على الأخرى.
في هذا المثال، يتم تصيير مكون Gallery من قبل مرتين بدون تغييرات على منطقه. جرب النقر على الأزرار داخل كل من المعارض. لاحظ أن حالتهما مستقلة:
هذا ما يجعل الحالة مختلفة عن المتغيرات العادية التي قد تعلن عنها في أعلى الوحدة النمطية (module) الخاصة بك. الحالة ليست مرتبطة باستدعاء دالة معينة أو مكان في الكود، بل هي “محلية” للمكان المحدد على الشاشة. لقد عرضت مكوّنين <Gallery />، لذلك يتم تخزين حالتهما بشكل منفصل.
لاحظ أيضًا كيف أن مكوّن Page لا “يعرف” أي شيء عن حالة Gallery أو حتى ما إذا كان لديه أي حالة. على عكس الـ props، الحالة خاصة تمامًا بالمكوّن الذي يعلن عنها. المكوّن الأب لا يمكنه تغييرها. هذا يتيح لك إضافة حالة إلى أي مكوّن أو إزالتها دون التأثير على باقي المكوّنات.
ماذا لو أردت الحفاظ على تزامن حالة كلا المعرضين؟ الطريقة الصحيحة للقيام بذلك في React هي إزالة الحالة من المكوّنات الأبناء وإضافتها إلى أقرب أب مشترك. ستركز الصفحات القليلة القادمة على تنظيم حالة مكوّن واحد، لكننا سنعود إلى هذا الموضوع في مشاركة الحالة بين المكوّنات.
خلاصة
- استخدم متغير حالة عندما يحتاج المكوّن إلى “تذكر” بعض المعلومات بين عمليات العرض (renders).
- يتم الإعلان عن متغيرات الحالة بواسطة استدعاء الـ Hook المسمى
useState. - الـ Hooks هي دوال خاصة تبدأ بكلمة
use. تتيح لك “الارتباط” بميزات React مثل الحالة. - قد تذكرك الـ Hooks بعمليات الاستيراد: يجب استدعاؤها بشكل غير مشروط. استدعاء الـ Hooks، بما في ذلك
useState، صالح فقط في المستوى الأعلى من مكوّن أو Hook آخر. - الـ Hook المسمى
useStateيُرجع زوجًا من القيم: الحالة الحالية والدالة لتحديثها. - يمكنك امتلاك أكثر من متغير حالة واحد. داخليًا، يطابقها React بناءً على ترتيبها.
- الحالة خاصة بالمكوّن. إذا عرضته في مكانين، تحصل كل نسخة على حالتها الخاصة.
تحدي 1 من 4: أكمل المعرض
عندما تضغط على “Next” في آخر منحوتة، ينهار الكود. أصلح المنطق لمنع الانهيار. يمكنك القيام بذلك عن طريق إضافة منطق إضافي إلى معالج الحدث أو عن طريق تعطيل الزر عندما لا يكون الإجراء ممكنًا.
بعد إصلاح الانهيار، أضف زر “Previous” يعرض المنحوتة السابقة. يجب ألا ينهار عند المنحوتة الأولى.