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

لكن في بعض الأحيان ، عند استخدام
useEffect
، لا
useEffect
مكونات آليات البرنامج مع بعضها بشكل جيد. يبدو لك أنك تفتقد شيئًا ما. كل هذا مشابه للعمل مع أحداث دورة حياة المكون المستندة إلى الفصل ... ولكن هل هو كذلك بالفعل؟
عند محاولة فهم ما لا يناسبك بالضبط ، تلاحظ أنك تطرح الأسئلة التالية:
- كيف تلعب
componentDidMount
باستخدام useEffect
؟ - كيفية تحميل البيانات داخل
useEffect
؟ ما هو []
؟ - هل يجب تحديد الوظائف كتبعيات للتأثير؟
- لماذا ينتهي البرنامج أحيانًا بحلقة لا تنتهي من إعادة تحميل البيانات؟
- لماذا تظهر الحالة القديمة أحيانًا داخل التأثيرات أم أن الخصائص القديمة موجودة؟
عندما بدأت استخدام الخطافات لأول مرة ، عذبتني هذه الأسئلة أيضًا. حتى عندما كنت أستعد الوثائق ، لم أستطع أن أقول أنني أتقن بعض التفاصيل الدقيقة. منذ ذلك الحين ، مررت بعدة لحظات ، عندما أدركت فجأة شيئًا مهمًا ، أردت حقًا أن أصرخ: "يوريكا!" حول ما أدركته في هذه اللحظات ، أريد أن أخبرك. ما تعلمته عن
useEffect
الآن سيسمح لك برؤية الإجابات الواضحة على الأسئلة أعلاه بوضوح.
ولكن من أجل الاطلاع على إجابات هذه الأسئلة ، نحتاج أولاً إلى التراجع. الغرض من هذه المقالة ليس إعطاء قرائها بعض الإرشادات خطوة بخطوة للعمل مع
useEffect
. إنه يهدف إلى مساعدتك ، إذا
useEffect
"
useEffect
"
useEffect
. وبصراحة ، ليس هناك الكثير لنتعلمه. في الواقع ، سنقضي معظم الوقت في نسيان ما عرفناه من قبل.
لم يجتمع كل شيء في رأسي إلا بعد أن توقفت عن النظر إلى خطاف
useEffect
خلال منظور الأساليب المألوفة لدورة حياة المكونات القائمة على المكونات.
"يجب أن تنسى ما تعلمته"
habr.com/ru/company/ruvds/blog/445276/من المفترض أن يكون قارئ هذه المادة معتادًا إلى حد ما على
useEffect API. هذا مقال طويل نوعا ما ، ويمكن مقارنته بكتاب صغير. الحقيقة هي أنني أفضل التعبير عن أفكاري بهذه الطريقة. أدناه ، باختصار شديد ، يتم إعطاء إجابات لتلك الأسئلة التي تمت مناقشتها أعلاه. ربما تكون مفيدة لأولئك الذين ليس لديهم الوقت أو الرغبة في قراءة جميع المواد.
إذا كان التنسيق الذي
useEffect
فيه
useEffect
، بكل
useEffect
، غير مناسب لك ، فيمكنك الانتظار قليلاً - حتى اللحظة التي تظهر فيها هذه التفسيرات في أدلة أخرى لا تعد ولا تحصى. إليكم نفس القصة مع مكتبة React نفسها ، والتي كانت في عام 2013 شيئًا جديدًا تمامًا. يستغرق مجتمع التطوير بعض الوقت حتى يتعرف على النموذج العقلي الجديد والمواد التعليمية المبنية على هذا النموذج لتظهر.
إجابات على الأسئلة
فيما يلي إجابات قصيرة للأسئلة التي تم طرحها في بداية هذه المادة ، والمخصصة لأولئك الذين لا يريدون قراءة هذا النص بالكامل. إذا شعرت أثناء قراءة هذه الإجابات أنك لا تفهم حقًا معنى ما تقرأه ، فابحث في المادة. سوف تجد تفسيرات مفصلة في النص. إذا كنت ستقرأ كل شيء ، فيمكنك تخطي هذا القسم.
to كيف يمكن لعب componentDidMount باستخدام useEffect؟
على الرغم من أنه يمكنك استخدام
useEffect(fn, [])
لتشغيل وظيفة
componentDidMount
، إلا أنها ليست المكافئ الدقيق لـ
componentDidMount
. وهي ، على عكس
componentDidMount
، تلتقط الخصائص والدولة. لذلك ، حتى داخل رد الاتصال ، سترى الخصائص الأولية والحالة. إذا كنت تريد أن ترى أحدث إصدار من شيء ما ، يمكنك كتابته في رابط
ref
. ولكن عادة ما يكون هناك طريقة أبسط لهيكلة الكود ، لذا فإن القيام بذلك اختياري. تذكر أن نموذج التأثيرات العقلية يختلف عن ذلك المطبق على
componentDidMount
وطرق دورة حياة المكون الأخرى. لذلك ، فإن محاولة العثور على معادلاتها الدقيقة يمكن أن تضر أكثر مما تنفع. من أجل العمل بشكل منتج ، تحتاج ، إذا جاز التعبير ، إلى "التفكير في الآثار". أساس نموذجهم العقلي أقرب إلى تنفيذ التزامن من الاستجابة للأحداث في دورة حياة المكونات.
to كيفية تحميل البيانات بشكل صحيح داخل useEffect؟ ما هو []؟
فيما يلي دليل جيد حول تحميل البيانات باستخدام
useEffect
. حاول قراءتها بالكامل! انها ليست كبيرة مثل ذلك. الأقواس ،
[]
، التي تمثل صفيفًا فارغًا ، تعني أن التأثير لا يستخدم القيم المشاركة في دفق بيانات React ، ولهذا السبب يمكن اعتبار استخدامه الفردي آمنًا. بالإضافة إلى ذلك ، يعد استخدام مجموعة فارغة من التبعيات مصدرًا شائعًا للأخطاء في حالة استخدام قيمة معينة بالفعل في التأثير. ستحتاج إلى إتقان العديد من الاستراتيجيات (المقدمة بشكل أساسي في شكل
useReducer
و
useCallback
) التي يمكن أن تساعد في القضاء على الحاجة إلى التبعية بدلاً من التخلص من هذه التبعية بشكل غير معقول.
need هل يجب تحديد الوظائف كتبعيات للتأثير؟
يوصى بأن تؤخذ الوظائف التي لا تحتاج إلى خصائص أو حالة خارج المكونات ، وتوصى بوضع تلك الوظائف التي تستخدم فقط بواسطة التأثيرات داخل التأثيرات. إذا
useCallback
بعد ذلك في استخدام الوظائف الموجودة في نطاق التجسيد (بما في ذلك الوظائف من الخصائص) ،
useCallback
في
useCallback
حيث تم التصريح عنها ، وحاول استخدامها مرة أخرى. لماذا هذا مهم؟ يمكن للوظائف "رؤية" القيم من الخصائص والحالة ، بحيث تشارك في تدفق البيانات.
إليك المزيد من المعلومات المفصلة حول هذا الأمر في الأسئلة الشائعة.
▍ لماذا ينتهي البرنامج أحيانًا بحلقة لا نهاية لها لإعادة تحميل البيانات؟
يمكن أن يحدث هذا عند تنفيذ تحميل البيانات بطريقة لا تحتوي على وسيطة ثانية تمثل التبعيات. بدونها ، يتم تنفيذ التأثيرات بعد كل عملية تجسيد - مما يعني أن تحديد الحالة سوف يتسبب في التذكير بهذه الآثار. يمكن أن تحدث حلقة لا نهائية أيضًا في حالة الإشارة إلى القيمة التي تتغير دائمًا في صفيف التبعية. تعرف على نوع القيمة الممكنة عن طريق إزالة التبعيات واحدة تلو الأخرى. ومع ذلك ، عادةً ما تكون إزالة التبعيات (أو استخدام rashly باستخدام
[]
الطريقة الخاطئة لحل مشكلة. بدلاً من ذلك ، يجب أن تجد مصدر المشكلة وحلها حقًا. على سبيل المثال ، يمكن أن تسبب الدالات مشكلة مماثلة. يمكنك المساعدة في حلها عن طريق وضعها في تأثيرات ، أو نقلها خارج المكونات ، أو عن طريق الالتفاف على
useCallback
. لتجنب إنشاء كائنات متعددة ، يمكنك استخدام
useMemo
.
sometimes لماذا تظهر الحالة القديمة في بعض الأحيان داخل الآثار أو يتم العثور على الخصائص القديمة؟
التأثيرات دائما "انظر" خصائص والدولة من تقديم التي أعلن عنها. يساعد هذا في
منع الأخطاء ، ولكن في بعض الحالات يمكن أن يتداخل مع التشغيل العادي للمكون. في مثل هذه الحالات ، يمكنك استخدام ارتباطات
ref
القابلة للتغيير صراحة للعمل مع هذه القيم (يمكنك قراءة ذلك في نهاية المقالة المذكورة أعلاه). إذا كنت تعتقد أنك ترى خصائص أو حالة من العرض القديم ، ولكن لا تتوقع ذلك ، فقد تكون قد فاتتك بعض التبعيات. من أجل معرفة كيفية رؤيتهم ، استخدم قاعدة اللنت. في غضون يومين ، سوف يصبح مثل طبيعتك الثانية. أيضًا ، ألق نظرة على
هذه الإجابة في الأسئلة الشائعة.
آمل أن تكون هذه الإجابات على الأسئلة مفيدة لأولئك الذين قرأوها. الآن دعونا نتحدث أكثر عن
useEffect
.
كل تقديم له خصائصه وحالته.
قبل أن نتمكن من مناقشة الآثار ، نحتاج إلى الحديث عن التقديم.
هنا هو مكون عداد وظيفي.
function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
ألق نظرة فاحصة على
<p>You clicked {count} times</p>
. ماذا تعني؟ هل الثابت الثابت بطريقة ما "يلاحظ" التغييرات في الحالة وهل يتم تحديثها تلقائيًا؟ يمكن اعتبار هذا الاستنتاج نوعًا من الفكرة الأولى القيمة لشخص يدرس React ، لكنها ليست
نموذجًا عقليًا دقيقًا لما يحدث.
في مثالنا ،
count
مجرد رقم. هذا ليس نوعًا من "ربط البيانات" السحري ، وليس نوعًا من "كائن المراقب" أو "الوكيل" ، أو أي شيء آخر. أمامنا رقم جيد قديم ، مثل هذا:
const count = 42;
أثناء إخراج المكون الأول ، تكون قيمة
count
تم الحصول عليها من
useState()
هي 0. عندما نسمي
setCount(1)
، يستدعي
setCount(1)
المكون مرة أخرى. سيكون هذا
count
الزمني 1. وهكذا:
React يستدعي المكون كلما قمنا بتحديث الحالة. ونتيجة لذلك ، فإن كل عملية تجسيد "ترى" قيمتها الخاصة بالحالة
counter
، والتي ، داخل الوظيفة ، ثابتة.
نتيجة لذلك ، لا يقوم هذا الخط بأي عملية ربط بيانات خاصة:
<p>You clicked {count} times</p>
يقوم فقط بتضمين قيمة عددية في الكود الذي تم إنشاؤه أثناء العرض. يتم توفير هذا الرقم بواسطة React. عندما نسمي
setCount
،
setCount
للمكون مرة أخرى بقيمة
count
مختلفة. React ثم يقوم بتحديث DOM بحيث يطابق طراز كائن المستند أحدث إخراج للبيانات أثناء تقديم المكون.
الاستنتاج الأكثر أهمية الذي يمكن استخلاصه من ذلك هو أن
count
ثابت داخل أي عرض معين ولا يتغير مع مرور الوقت. يتغير المكون الذي يتم استدعاؤه مرارًا وتكرارًا. كل تجسيد "يرى" قيمة
count
الخاصة به ، والتي يتم عزلها لكل عملية تجسيد.
في
هذه المادة ، يمكنك العثور على تفاصيل حول هذه العملية.
كل تقديم له معالجات الأحداث الخاصة به.
كل شيء لا يزال واضحا. ماذا عن معالجات الأحداث؟
نلقي نظرة على هذا المثال. هنا ، بعد ثلاث ثوانٍ من النقر فوق الزر ، يتم عرض مربع رسالة يحتوي على معلومات حول القيمة المخزنة في
count
:
function Counter() { const [count, setCount] = useState(0); function handleAlertClick() { setTimeout(() => { alert('You clicked on: ' + count); }, 3000); } return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> <button onClick={handleAlertClick}> Show alert </button> </div> ); }
افترض أنني أؤدي تسلسل الإجراءات التالي:
- سأرفع قيمة
count
إلى 3 بالنقر Click me
الزر "النقر Click me
. - انقر فوق الزر "
Show alert
. - زيادة القيمة إلى 5 قبل انتهاء المهلة.
زيادة قيمة العدد بعد النقر فوق الزر "إظهار التنبيه"ما رأيك يظهر في مربع الرسالة؟ هل سيتم عرض الرقم 5 هناك ، وهو ما يتوافق مع قيمة
count
في الوقت الذي تم فيه تشغيل المؤقت ، أو 3 - أي قيمة
count
في الوقت الذي يتم فيه الضغط على الزر؟
ستجد الآن إجابة على هذا السؤال ، ولكن إذا كنت ترغب في معرفة كل شيء بنفسك -
إليك نسخة صالحة من هذا المثال.
إذا كان ما رأيته يبدو غير مفهوم بالنسبة لك - فإليك مثال أقرب إلى الواقع. تخيل تطبيق الدردشة الذي يتم فيه ، في الولاية ، تخزين
ID
المستلم الحالي للرسالة ، وهناك زر
Send
. في
هذه المادة ، ما يحدث يعتبر بالتفصيل. في الواقع ، الإجابة الصحيحة على سؤال ما يظهر في مربع الرسالة هي 3.
آلية عرض مربع رسالة "استولت" على الحالة في الوقت الذي تم فيه النقر على الزر.
هناك طرق لتطبيق إصدار آخر من السلوك ، ولكن الآن سنتعامل مع السلوك القياسي للنظام. عند بناء النماذج الذهنية للتكنولوجيات ، من المهم التمييز بين "الطريق الأقل مقاومة" وبين جميع أنواع "مخارج الطوارئ".
كيف يعمل كل هذا؟
لقد قلنا بالفعل أن قيمة
count
ثابتة لكل مكالمة محددة لوظائفنا. أعتقد أنه من المفيد الحديث عن هذا بمزيد من التفصيل. النقطة المهمة هي أن وظيفتنا تسمى عدة مرات (مرة واحدة لكل عملية تجسيد) ، ولكن مع كل من هذه المكالمات ،
count
داخلها ثابتًا. تم ضبط هذا الثابت على قيمة معينة (تمثل حالة عملية تقديم معينة).
هذا السلوك للوظائف ليس شيئًا خاصًا لـ React - الوظائف العادية تتصرف بطريقة مماثلة:
function sayHi(person) { const name = person.name; setTimeout(() => { alert('Hello, ' + name); }, 3000); } let someone = {name: 'Dan'}; sayHi(someone); someone = {name: 'Yuzhi'}; sayHi(someone); someone = {name: 'Dominic'}; sayHi(someone);
في
هذا المثال ،
someone
إعادة تعيين المتغير الخارجي
someone
عدة مرات. يمكن أن يحدث نفس الشيء في مكان ما داخل React ، قد تتغير الحالة الحالية للمكون. ومع ذلك ، يوجد داخل دالة
sayHi
name
ثابت محلي مرتبط
person
من مكالمة معينة. هذا الثابت محلي ، وبالتالي يتم عزل قيمه في استدعاءات الوظائف المختلفة عن بعضها البعض! نتيجةً لذلك ، بعد انقضاء مهلة زمنية ، "تتذكر" نافذة الرسالة المعروضة قيمة
name
الخاصة بها.
هذا ما يفسر كيف يلتقط معالج الأحداث قيمة
count
عند النقر فوق زر. إذا قمنا ، مع المكونات ، بتطبيق نفس المبدأ ، اتضح أن كل "يرى" يرى قيمة
count
الخاصة به:
نتيجة لذلك ، يقوم كل
handleAlertClick
، في الواقع ، بإرجاع
handleAlertClick
"الإصدار"
handleAlertClick
. كل من هذه الإصدارات "يتذكر" قيمة
count
الخاصة به:
لهذا السبب ، في
هذا المثال ، "تنتمي" معالجات الأحداث إلى عروض محددة ، وعند النقر فوق الزر ، يستخدم المكون حالة
count
من هذه العروض.
ضمن كل تجسيد معين ، تظل الخصائص والحالة دائمًا كما هي. لكن إذا استخدمت عمليات تقديم مختلفة خصائصها وحالتها ، يحدث نفس الشيء مع أي آليات تستخدمها (بما في ذلك معالجات الأحداث). هم أيضا "ينتمون" إلى عروض محددة. لذلك ، حتى "الدالات" غير المتزامنة داخل معالجات الأحداث "سترى" نفس قيم
count
.
تجدر الإشارة إلى أنه في المثال أعلاه ، قمت بدمج قيم
count
معين مباشرة في وظيفة
handleAlertClick
. لن يؤذينا هذا الاستبدال "العقلي" ، حيث لا يمكن تغيير
count
الثابت داخل عرض معين. أولاً ، إنه ثابت ، وثانيًا ، إنه رقم. من الآمن القول أنه يمكن للمرء أن يفكر أيضًا في معاني أخرى ، مثل الكائنات ، ولكن فقط إذا قبلنا كقاعدة بعدم إجراء تغييرات (الطفرات) في الدولة. في الوقت نفسه ، نحن راضون عن الدعوة إلى
setSomething(newObj)
لكائن جديد بدلاً من تغيير الكائن الحالي ، حيث أنه من خلال هذا النهج لم يتم المساس بالحالة التي تنتمي إلى العرض السابق.
كل تقديم له آثاره الخاصة.
هذه المادة ، كما تعلمون ، مخصصة للآثار ، لكننا لم نتحدث عنها حتى الآن. الآن سوف نصلحها. كما اتضح ، فإن العمل مع التأثيرات لا يختلف بشكل خاص عما توصلنا إليه بالفعل.
تأمل
مثالاً من الوثائق ، وهو يشبه إلى حد كبير
المثال الذي قمنا بتحليله بالفعل:
function Counter() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
الآن لدي سؤال لك. كيف يقرأ التأثير أحدث قيمة
count
؟
ربما يتم استخدام بعض "ربط البيانات" هنا ، أو "كائن مراقب" يقوم بتحديث قيمة
count
داخل وظيفة التأثير؟ ربما يكون
count
متغيرًا قابلاً للتغيير الذي تحدد قيمته React داخل مكوننا ، ونتيجة لذلك يرى التأثير دائمًا أحدث إصدار له؟
لا.
نحن نعلم بالفعل أنه في تقديم عنصر معين ،
count
ثابتًا. حتى معالجات الأحداث "يرون" قيمة
count
من التجسيد الذي "ينتمون إليه" نظرًا لحقيقة أن
count
ثابت في نطاق معين. وينطبق الشيء نفسه بالنسبة للآثار!
وتجدر الإشارة إلى أن هذا ليس هو
count
المتغيرات
count
والذي يتغير بطريقة ما داخل تأثير "لم يتغير". أمامنا هي وظيفة التأثير نفسه ، والتي تختلف في كل عملية تقديم.
كل إصدار "يرى" قيمة
count
من التجسيد الذي ينتمي إليه:
React , DOM .
, ( ), , , , «» , «».
, , .
, ( ,
). , , , .
, , :
React:
:
- :
<p>You clicked 0 times</p>
. - , , :
() => { document.title = 'You clicked 0 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 0 times' }
.
, . , , - :
:
React:
:
- :
<p>You clicked 1 times</p>
. - , , :
() => { document.title = 'You clicked 1 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 1 times' }
.
…
, , , , «» .
. :
function Counter() { const [count, setCount] = useState(0); useEffect(() => { setTimeout(() => { console.log(`You clicked ${count} times`); }, 3000); }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
, ?
, . , , , . ! , , , , ,
count
.
.
: «, ! ?».
, ,
this.setState
, , . , ,
, , , :
componentDidUpdate() { setTimeout(() => { console.log(`You clicked ${this.state.count} times`); }, 3000); }
,
this.state.count
count
, , . , , , 5 , 5 .
, JavaScript-, , ,
, ,
setTimeout
, . , (React
this.state
, ), .
— , , «» , . , , , . , , . , , , , , ,
.
, ( , , - API ) , .
:
function Example(props) { useEffect(() => { setTimeout(() => { console.log(props.counter); }, 1000); });
, «» . ! . , .
, , - , , , , . ,
ref
,
.
, , , , , . , ( ), «» React-. , , . , .
, , , :
function Example() { const [count, setCount] = useState(0); const latestCount = useRef(count); useEffect(() => {
- React . React
this.state
. , ,
latestCount.current
. , . , , , .
?
, . , , «» .
:
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange); }; });
,
props
—
{id: 10}
,
{id: 20}
— . , :
- React
{id: 10}
. - React
{id: 20}
. - React
{id: 20}
.
( , , .)
, «» - , , «» - , . — , , , . .
React
, . , . . . :
- React
{id: 20}
. - .
{id: 20}
. - React
{id: 10}
. - React
{id: 20}
.
, «»
props
,
{id: 10}
, ,
props
{id: 20}
.
, …
— ?: « ( , , - API ) , ».
! « » , . , , :
, , … , «» , -,
{id: 10}
.
React . , , .
props
, .
,
React , .
.
, :
function Greeting({ name }) { return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
,
<Greeting name="Dan" />
, —
<Greeting name="Yuzhi" />
,
<Greeting name="Yuzhi" />
.
Hello, Yuzhi
.
, , . React, . , , .
$.addClass
$.removeClass
jQuery- ( — , «»), , CSS- React ( — , «»).
React DOM , . «» «».
.
useEffect
, React, .
function Greeting({ name }) { useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
useEffect
, , . , - , ! , «», «».
,
A
,
B
, —
C
, ,
C
. (, - ), .
, , , . ( ).
?
React
React DOM. DOM , React DOM, - .
, :
<h1 className="Greeting"> Hello, Dan </h1>
:
<h1 className="Greeting"> Hello, Yuzhi </h1>
React :
const oldProps = {className: 'Greeting', children: 'Hello, Dan'}; const newProps = {className: 'Greeting', children: 'Hello, Yuzhi'};
React ,
children
, DOM. ,
className
. :
domNode.innerText = 'Hello, Yuzhi';
- ? , , .
, , - :
function Greeting({ name }) { const [counter, setCounter] = useState(0); useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} <button onClick={() => setCounter(counter + 1)}> Increment </button> </h1> ); }
counter
.
document.title
name
,
name
.
document.title
counter
, .
React … ?
let oldEffect = () => { document.title = 'Hello, Dan'; }; let newEffect = () => { document.title = 'Hello, Dan'; };
— . React , , . ( .
name
.)
, , (
deps
),
useEffect
:
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
, React: «, , , ,
name
».
, , React :
const oldEffect = () => { document.title = 'Hello, Dan'; }; const oldDeps = ['Dan']; const newEffect = () => { document.title = 'Hello, Dan'; }; const newDeps = ['Dan'];
, , ! - - .
React
React — . , , , ,
useEffect
, , , . ( !)
function SearchResults() { async function fetchData() {
FAQ , . .
« !», — . : , , . , , , — , .
, , . , , , , . , . .
, , .
, React
, , React , .
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
—, , ,
[]
, , , , :
useEffect(() => { document.title = 'Hello, ' + name; }, []);
—. , «» , , .
, , , . , : «
setInterval
clearInterval
».
. , , ,
useEffect
, , ,
[]
. - , ?
function Counter() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, []); return <h1>{count}</h1>; }
, ,
.
, « , », . , , ,
setInterval
, . , ?
, — React , , . ,
count
, React , , , . — .
count
0.
setCount(count + 1)
setCount(0 + 1)
. , —
[]
,
setCount(0 + 1)
:
React, , , — .
count
— , ( ):
const count =
. React .
,. , , React , , . —
- .
React , . , , , .
, , , .
count
:
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
. , , — , .
count
,
count
,
setCount(count + 1)
:
,
setInterval
,
count
, . , .
,, , , . — , .
.
,
count
.
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
, ,
count
. ,
count
setCount
. , ,
count
. , ,
setState
:
useEffect(() => { const id = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(id); }, []);
« ». ,
count
- ,
setCount(count + 1)
.
count
- ,
count + 1
«» React. React
count
. , React — , , , .
setCount(c => c + 1)
. « React », , . « » , ,
.
, , , . React.
count
:
,.
,
setInterval
, ,
c => c + 1
.
count
. React .
Google Docs
, , — ? , , «», , . , Google Docs . . , .
, . . ,
setCount(c => c + 1)
, ,
setCount(count + 1)
, «»
count
. , ( — «»). « React» —
. .
( ) , Google Docs
. — , React . , , ( , , ) .
,
setCount(c => c + 1)
, . , . , , , , , .
setCount(c => c + 1)
.
useReducer
.
, :
count
step
.
setInterval
,
step
:
function Counter() { const [count, setCount] = useState(0); const [step, setStep] = useState(1); useEffect(() => { const id = setInterval(() => { setCount(c => c + step); }, 1000); return () => clearInterval(id); }, [step]); return ( <> <h1>{count}</h1> <input value={step} onChange={e => setStep(Number(e.target.value))} /> </> ); }
.
, React .
step
, . .
:
step
setInterval
—
step
. , , , ! , , , , , .
, , ,
setInterval
,
step
.
step
?
, ,
useReducer
.
,
setSomething(something => ...)
, , . «», , , .
step
dispatch
:
const [state, dispatch] = useReducer(reducer, initialState); const { count, step } = state; useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' });
.
: « , ?». , React ,
dispatch
. .
!
(
dispatch
setstate
useRef
, React , . — .)
, , , , .
step
. , . , . :
const initialState = { count: 0, step: 1, }; function reducer(state, action) { const { count, step } = state; if (action.type === 'tick') { return { count: count + step, step }; } else if (action.type === 'step') { return { count, step: action.step }; } else { throw new Error(); } }
, , , .
useReducer — -
, , , . , , ? , , API
<Counter step={1} />
. ,
props.step
?
, ! , :
function Counter({ step }) { const [count, dispatch] = useReducer(reducer, 0); function reducer(state, action) { if (action.type === 'tick') { return state + step; } else { throw new Error(); } } useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' }); }, 1000); return () => clearInterval(id); }, [dispatch]); return <h1>{count}</h1>; }
, . , , , , .
.
dispatch
. , , . .
, , . «» , , ? ,
dispatch
, React . . .
useReducer
«-» . , . , , , , .
, - , .
, , , :
function SearchResults() { const [data, setData] = useState({ hits: [] }); async function fetchData() { const result = await axios( 'https://hn.algolia.com/api/v1/search?query=react', ); setData(result.data); } useEffect(() => { fetchData(); }, []);
, .
, , . , , , , , , , , .
, , , , :
function SearchResults() {
, , :
function SearchResults() { const [query, setQuery] = useState('react');
, (, ), . .
, . , :
function SearchResults() {
.
? , « ». React, - .
getFetchUrl
,
query
, , , , . — ,
query
:
function SearchResults() { const [query, setQuery] = useState('react'); useEffect(() => { function getFetchUrl() { return 'https://hn.algolia.com/api/v1/search?query=' + query; } async function fetchData() { const result = await axios(getFetchUrl()); setData(result.data); } fetchData(); }, [query]);
.
, « React».
query
. , , , , . , , .
exhaustive-deps
eslint-plugin-react-hooks
, . , , .
.
, ?
. , , . , , .
? , . : React . . , « ». , , . , , , !
, , . ,
getFetchUrl
:
function SearchResults() { function getFetchUrl(query) { return 'https://hn.algolia.com/api/v1/search?query=' + query; } useEffect(() => { const url = getFetchUrl('react');
getFetchUrl
— , .
, «» , .
getFetchUrl
(, , ), :
function SearchResults() {
,
getFetchUrl
. , — . - , , . , , , .
— .
, , :
, . , , .
. ,
useCallback :
function SearchResults() {
useCallback
. : , -, , , .
, . (
'react'
'redux'
). , , ,
query
. , ,
query
,
getFetchUrl
.
,
query
useCallback
:
function SearchResults() { const [query, setQuery] = useState('react'); const getFetchUrl = useCallback(() => {
useCallback
query
, ,
getFetchUrl
,
query
:
function SearchResults() { const [query, setQuery] = useState('react');
useCallback
,
query
,
getFetchUrl
, , .
query
,
getFetchUrl
, . Excel: - , , , .
— , . , :
function Parent() { const [query, setQuery] = useState('react');
fetchData
Parent
query
,
Child
, .
?
, , , , . , , , , :
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, : « , , ,
useEffect
—
componentDidMount
componentDidUpdate
. !».
componentDidUpdate
:
class Child extends Component { state = { data: null }; componentDidMount() { this.props.fetchData(); } componentDidUpdate(prevProps) {
,
fetchData
— ! (, , , .) - , .
this.props.fetchData
prevProps.fetchData
. , , ?
componentDidUpdate(prevProps) { this.props.fetchData(); }
. . ( .) ,
fetchData
this.state.query
?
render() { return <Child fetchData={this.fetchData.bind(this, this.state.query)} />; }
this.props.fetchData !== prevProps.fetchData
true
, ,
query
! .
, , ,
query
Child
. , ,
query
,
query
:
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, , - , , .
, , .
this
, . , , , , - . ,
this.props.fetchData
, , , , , .
-
useCallback
. , , , . , .
useCallback
props.fetchData
.
,
useMemo
:
function ColorPicker() {
,
useCallback
, - . « », , , . , . ,
.
,
fetchData
( ), . , , . («
props.onComplete
, ?») , .
, :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . . — , :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } componentDidUpdate(prevProps) { if (prevProps.id !== this.props.id) { this.fetchData(this.props.id); } } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . , . ,
{id: 10}
,
{id: 20}
, , . , , , . وهذا خطأ.
, , . — , ,
async/await
( , - ) , ( , ).
,
async
-. (, , , , .)
, , ! .
, :
function Article({ id }) { const [article, setArticle] = useState(null); useEffect(() => { let didCancel = false; async function fetchData() { const article = await API.fetchArticle(id); if (!didCancel) { setArticle(article); } } fetchData(); return () => { didCancel = true; }; }, [id]);
, , , . , .
, , , , , . , , , . . — .
useEffect
, , , . React. ,
useEffect
.
, , « », . . , , , , «» , .
,
useEffect
, . — . — , , — , . , , , , API.
, ,
useFetch
, ,
useTheme
, . , ,
useEffect
. , , , .
, ,
useEffect
. — , . , . ?
Suspense React , , - ( : , , ) .
Suspense
, ,
useEffect
, , , - . , , , . , ,
, , .
النتائج
, . , , - , , , .
