React/hooks reference

من موسوعة حسوب
مراجعة 13:22، 16 فبراير 2019 بواسطة جميل-بيلوني (نقاش | مساهمات) (إنشاء الصفحة)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

الخطافات هي إضافة جديدة إلى الإصدار 16.8 في React، إذ تسمح لك باستعمال ميزة الحالة وميزات React الأخرى دون كتابة أي صنف.

تشرح هذه الصفحة الواجهات البرمجية للخطافات المضمَّنة في React.

إن كان موضوع الخطافات جديدًا بالنسبة لك، فيرجى الرجوع إلى صفحة مدخل إلى الخطافات وقراءتها أولًا. قد تجد أيضًا الكثير من المعلومات المفيدة في قسم الأسئلة الشائعة.

الخطافات الأساسية

useState

const [state, setState] = useState(initialState);

يعيد قيمةً ذات حالة، ودالةً لتحديث هذه القيمة.

أثناء عملية التصيير الأولية، الحالة المعادة (state) هي نفسها القيمة المُمرَّرة كأول وسيط (initialState).

تُستعمَل الدالة setState لتحديث الحالة، إذ تقبل قيمة جديدة للحالة وتدرج في الطابور عملية إعادة تصيير لمكون.

setState(newState);

أثناء عمليات إعادة التصيير اللاحقة، القيمة الأولى التي يعيدها الخطاف useState ستبقى دومًا أحدث حالة بعد تطبيق التحديثات.

تحديثات عبر تمرير دالة

إن حُسبَت الحالة الجديدة باستعمال الحالة السابقة، فيمكنك تمرير دالة إلى setState.ستستقبل الدالة القيمة السابقة، وتعيد القيمة المحدَّثة. إليك مثالٌ عن مكون عداد يستعمل كلا الشكلين للخطاف setState:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(initialCount)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    </>
  );
}

يستعمل الزر "+" والزر "-" الشكل الدالِّي (functional form) لأن القيمة المحدَّثة تعتمد على القيمة السابقة. ولكن الزر "Reset" يستعمل الشكل الاعتيادي لأنه يضبط العداد إلى القيمة 0 دومًا. ملاحظة: خلافًا للتابع setState في مكونات الأصناف، الخطاف useState لا يدمج كائنات التحديث (update objects). يمكنك تكرار هذا السلوك عبر دمج شكل الدالة المحدِّثة مع معامل النشر للكائن:

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

هنالك خيار آخر وهو استعمال الخطاف useReducer الذي يعد مناسبًا لإدارة كائنات حالة تحوي عدة قيمة فرعية.

الحالة الأولية الكسولة

الوسيط initialState هو الحالة المستعملة أثناء عملية التصيير الأولى (initial render). في عمليات التصيير اللاحقة، سيهمل هذا الوسيط. إن كانت الحالة الأولية هي ناتج عملية حساب معقدة تؤثر على الأداء، فيمكنك أن تمرر دالة عوضًا عن ذلك والتي ستُنفَّذ مرةً واحدةً في أول عملية تصيير:

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

عدم تغير الحالة عن إجراء تحديث عليها

إن حدَّث خطاف حالة وكانت القيمة المحدَّثة نفسَ قيمة الحالة الحالية، فلن تتكبد React عنا تصيير الابن أو تنفيذ التأثيرات. (تستعمل React الخوارزمية Object.is لإجراء عملية الموازنة.)

useEffect

useEffect(didUpdate);

يقبل هذا الخطاف دالةً تحوي أمرًا يكون غالبًا شيفرة ذات تأثير.

التعديلات، والاشتراكات، والمؤقتات، والسجلات، والتسجيل (logging)، والتأثيرات الجانبية الأخرى غير مسموح بها داخل الجسم الرئيسي لمكون دالة (يشار إليه على أنَّه مرحلة تصيير React [أي render phase]). سيؤدي فعل ذلك إلى حصول أخطاءٍ مربكة مع تناقضات في واجهة المستخدم.

عوضًا عن ذلك، استعمل الخطاف useEffect. الدالة المُمرَّر إليه ستُنفَّذ بعد الانتهاء من التصيير على الشاشة. فكر في التأثيرات وكأنها مخرج هروب (escape hatch) من عالم React الوظيفي البحت إلى العالم الأمري.

افتراضيًّا، تُنفَّذ التأثيرات بعد كل كل عملية تصيير مكتملة، ولكن يمكنك اختيار تنفيذها فقط عند تغير قيم محدَّدة.

تنظيف تأثير

تنشئ التأثيرات غالبًا موارد تحتاج للتنظيف قبل أن يغادر المكون الشاشة مثل معرِّف اشتراك أو مؤقت. لفعل ذلك، قد تعيد الدالة المُمرَّرة إلى الخطاف useEffect دالةً تجري عملية التنظيف. على سبيل المثال، لإنشاء اشتراك:

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // تنظيف الاشتراك
    subscription.unsubscribe();
  };
});

تُنفَّذ دالة التنظيف قبل حذف المكون من واجهة المستخدم لمنع حدوث تسريب في الذاكرة. أضف إلى ذلك أنَّه إن صيَّر مكوِّنٌ عدة مرات (كما تفعل عادةً)، فسيُنظَّف التأثير السابق قبل تنفيذ التأثير اللاحق. في مثالنا، هذا يعني أنَّه يُنشَأ اشتراك جديد في كل تحديث. لتجنب تنفيذ التأثير عند كل عملية تحديث، ارجع إلى القسم التالي.

توقيت التأثيرات

خلافًا للتابعين componentDidMount و componentDidUpdate، تُنفَّذ الدالة المُمرَّرة إلى الخطاف useEffect بعد التخطيط والرسم أثناء حدث مؤجل (deferred event). هذا يجعلها مناسبة للاستعمال مع العديد من التأثيرات الجانبية الشائعة مثل ضبط الاشتراكات ومعالجات الحدث لأن أغلب أنواع العمل لا يجب أن يحجز المتصفح عن تحديث الشاشة.

على أية حال، لا يمكن تأجيل جميع التأثيرات. على سبيل المثال، التعديلات التي تجرى على DOM والظاهرة للمستخدم يجب أن تُنفَّذ بشكل متزامن قبل تنفيذ عملية الرسم التالية، لذا لا يلاحظ المستخدم تناقضات بصرية. (الفارق من ناحية النظرية مشابهٌ للفارق بين مستمعي حدث نشطين مقابل مستمعي حدث خاملين.) توفر React من أجل هذه الأنواع من التأثيرات خطافًا إضافيًّا يدعى useLayoutEffect. يملك هذا الخطاف نفس التوقيع الذي يملكه الخطاف useEffect. الاختلاف الوحيد بينهما هو وقت التنفيذ.

رغم أن الخطاف useEffect مؤجل لبعد انتهاء المتصفح من الرسم، فإن تنفيذه قبل أية عمليات تصيير أخرى أمرٌ مؤكد الحدوث، إذ تنفذ React أية تأثيرات لتصيير سابق قبل بدء تحديث جديد.

تنفيذ تأثير شرطيًّا

السلوك الافتراضي للتأثيرات هو تنفيذ التصيير بعد كل عملية تصيير مكتملة. بهذه الطريقة، يعاد إنشاء تأثيرٍ دومًا إن تغيرت إحدى مدخلاته.

على أية حال، هذا السلوك قد يبدو مبالغًا فيه بشدة في بعض الحالات مثل مثال الاشتراك من القسم السابق. لا نحتاج إلى إنشاء اشتراك جديد في كل تحديث إلا إذا تغيرات الخاصية source.

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

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);

الآن، سيعاد إنشاء الاشتراك عند تغيِّر props.source.

تمرير مصفوفة فارغة [] من المدخلات يخبر React أن تأثيراتك لا تعتمد على أية قيم من المكونات؛ لذلك، سيُنفَّذ ذلك التأثير عند الوصل (mount) ويُنظَّف عند الفصل (unmount) ولن تُنفَّذ عند التحديثات.

ملاحظة: مصفوفة المدخلات لا تُمرَّر كوسائط إلى دالة التأثير. نظريًّا، إليك ما الذي تمثله: كل قيمة أشير إليها داخل دالة التأثير يجب أن تظهر أيضًا في مصفوفة المدخلات. في المستقبل، قد يصبح المصرف متقدم بما فيه الكفاية لإنشاء هذه المصفوفة تلقائيًا.

useContext

const context = useContext(Context);

يقبل هذا الخطاف كائن سياق (context object، أي القيمة المعادة من React.createContext) ويعيد قيمة السياق الحالي كما أُعطيَت من قبل أقرب موفر سياق (context provider) للسياق المعطى.

عندما يتحدث السياق، سيُطلِق (trigger) هذا الخطاف عملية تصيير مع أحدث قيمة للسياق.