useCallback – رمزگشایی از React Hooks (Pt. 1)

در این مقاله، زمان و نحوه استفاده از React را بررسی خواهیم کرد useCallback
قلاب و اشتباهی که اکثر توسعه دهندگان جوان مرتکب شده اند.
اگر میخواهید این را ببندید و به صورت محلی اجرا کنید، مخزن را میتوانید در اینجا پیدا کنید
شروع شدن
fork and clone
cd client
npm i
npm start
برابری مرجع
برابری ارجاعی یک مفهوم اساسی در جاوا اسکریپت و علوم کامپیوتر به عنوان یک کل است. پس بیایید با نمایش آن در عمل شروع کنیم.
شما به سادگی می توانید همراه یا اجرا کنید referentialEquality.js
برای مشاهده خروجی
console.log(1 === 1);
// prints true
هنگام ارزیابی اینکه آیا integer 1
کاملاً برابر است integer 1
، کنسول چاپ می کند true
. این به این دلیل است که، خوب … integer 1
است کاملاً برابر با integer 1
.
هنگام ارزیابی دو رشته، نتیجه یکسانی را مشاهده می کنیم.
console.log('Referential Equality' === 'Referential Equality');
// prints true
بدیهی است که این همیشه برای دو نوع داده اولیه با یک مقدار صادق خواهد بود.
حال، ساختار داده چطور؟ برای مثال، دو شئ با جفت کلید/مقدار یکسان؟ در مورد لفظ شیء خالی چطور؟
console.log({ a: 1 } === { a: 1 });
// prints false
چرا این چاپ false
? هنگام مقایسه اینکه آیا این دو لفظ شی کاملاً برابر هستند یا خیر، جاوا اسکریپت از متن مربوط به آنها استفاده می کند آدرس های حافظه.
به عبارت دیگر، این دو شیء ممکن است حاوی یکسان باشند ارزش های، اما آنها نیستند ارجاع به همان شی. آنها نگاه کن یکسان است اما دو متفاوت را اشغال می کند فضاهای حافظه.
این امر چه در حال مقایسه دو کلمه شیء، دو کلمه آرایه یا دو تابع باشد، صدق می کند!
console.log({} === {});
// prints false
console.log([1, 2, 3] === [1, 2, 3]);
// prints false
console.log([] === []);
// prints false
برای نشان دادن بیشتر این موضوع، یک تابع تعریف می کنیم func
، که یک تابع ناشناس را برمی گرداند که به نوبه خود چیز دیگری را برمی گرداند (مانند یک عنصر JSX).
const func = () => {
return () => 'This is a pretend component.';
};
سپس دو تابع مختلف را اختصاص می دهیم، firstRender
و secondRender
، برابر با مقدار بازگردانده شده توسط func
.
const firstRender = func();
const secondRender = func();
در فکر
func
به عنوان جزء عملکردی React شما، در حالی کهfirstRender
یک تابع _inside_ از آن در اولین رندر است وsecondRender
یک تابع _inside_ آن در رندر دوم است.
بااینکه firstRender
و secondRender
یکسان به نظر می رسند، همان مقدار را برمی گردانند، و حتی مقدار آنها از همان تعریف به آنها اختصاص داده می شود، آنها ندارند برابری ارجاعی. در نتیجه هر بار که مولفه والد رندر می شود، این تابع را دوباره تعریف می کند.
console.log(firstRender === secondRender);
// false
متأسفانه، در جاوا اسکریپت، چاپ این آدرس های حافظه مانند پایتون آسان نیست، اما برای توضیح کمی عمیق تر از مرجع در مقابل مقدار، به این مقاله نگاهی بیندازید.
این موضوع می تواند متراکم شود و نیازی نیست امشب کلاسی در مورد آن تدریس کنید. بنابراین در حال حاضر، فقط به یاد داشته باشید:
- نوع داده اولیه
===
نوع داده اولیه - ساختار داده ها
!==
ساختار داده ها.
با وجود برابری ارجاعی، بیایید به کد React خود بپردازیم و ببینیم چرا این موضوع مرتبط است.
کد شروع
با مشاهده کد ارائه شده شروع کنید، سپس ابزار توسعه دهنده خود را باز کنید. تا مدتی دیگر از کنسول مرورگر استفاده خواهیم کرد.
پس از چرخش برنامه خود، آن را باز کنید BookDetails.jsx
جزء و دوباره ذخیره کنید. اولین چیزی که ممکن است در سرور توسعه React خود متوجه شویم، یک چیز رایج است WARNING
که توسعه دهندگان جوان تمایل به نادیده گرفتن آن دارند. همانطور که شما به نیروی کار ضربه می زنید و شروع به نوشتن کد برای تولید می کنید، لنگرهای شما حتی سخت تر از آنچه در آن تعبیه شده است می شود. create-react-app
. WARNINGS
تبدیل خواهد شد ERRORS
، و برخی از قوانین لینتر حتی به شما اجازه نمی دهند بدون پرداختن به این موارد فشار دهید ERRORS
.
و خود را آماده کن؛ اکثر لنگرها اجازه نمی دهند console.logs
در کد شما بنابراین هر چه زودتر روش صحیح را یاد بگیرید، بهتر است. بنابراین به جای نادیده گرفتن آن، بیایید نحوه درمان آن را دریابیم.
WARNING in [eslint]
src/components/BookDetails.jsx
Line 18:6: React Hook useEffect has a missing dependency: 'getBookDetails'. Either include it or remove the dependency array react-hooks/exhaustive-deps
webpack compiled with 1 warning
توجه: ممکن است ابتدا لازم باشد BookDetails.jsx را دوباره برای ایجاد این ذخیره کنید WARNING
اگر در React Docs بگردیم، میتوانیم راهحلهای پیشنهادی نیمه گیجکننده برای این موضوع را رمزگشایی کنیم. WARNING
به شرح زیر است:
لحظه ای به عواقب هر گزینه فکر کنید.
- شامل تعریف تابع در داخل
useEffect
ما نمی توانیم این تابع را در جای دیگری فراخوانی کنیم مگر اینکه آن را دوباره تعریف کنیم.
- آرایه وابستگی را حذف کنید.
این باعث می شود
useEffect
هر زمان وضعیت یا props تغییر میکند، معمولاً باعث ایجاد یک رندر مجدد بینهایت میشود، و در مورد ما، میتواند API ما را با درخواستهای بینهایت بارگذاری کند.
- فراخوانی تابع را از قسمت حذف کنید
useEffect
.
تابع فراخوانی نمی شود.
- تابع را در آرایه وابستگی قرار دهید.
اولین باری که کامپوننت رندر میشود، تابع ما را تعریف میکند، که باعث میشود useEffect، که باعث میشود کامپوننت دوباره رندر شود، که تابع را دوباره تعریف میکند، که باعث میشود useEffect، که باعث میشود کامپوننت دوباره رندر شود. ، که عملکرد را دوباره تعریف می کند …
بنابراین … یک توسعه دهنده چه کاری باید انجام دهد؟
سادهترین و ارجحترین راهحل، «شامل آن» است، یعنی جابهجایی getBookDetails
تعریف تابع در داخل useEffect
. این به یک اصل برنامه نویسی شی گرا معروف به کپسولاسیون پایبند است.
اما فرض کنید می دانیم که باید تابع را در جای دیگری فراخوانی کنیم. آیا باید بعداً آن را دوباره تعریف کنیم؟ این برای ما خیلی خشک نیست.
بیایید آرایه وابستگی خود را به گونه ای تغییر دهیم که مرجع تابع ما باشد. شما useEffect
اکنون باید به این شکل باشد
useEffect(() => {
getBookDetails();
}, [getBookDetails]);
و getBookDetails
تعریف شده باقی می ماند در بالا را useEffect
.
const getBookDetails = async () => {
const res = await axios.get(`${BASE_URL}/${id}`);
setBook(res.data);
console.log(res.data);
};
حالا ما یک جدید داریم WARNING
:
WARNING in [eslint]
src/components/BookDetails.jsx
Line 10:9: The 'getBookDetails' function makes the dependencies of useEffect Hook (at line 18) change on every render. Move it inside the useEffect callback. Alternatively, wrap the definition of 'getBookDetails' in its own useCallback() Hook react-hooks/exhaustive-deps
webpack compiled with 1 warning
را وارد کنید useCallback
قلاب
به طور خلاصه، useCallback
hook به شما امکان میدهد تا یک تابع را بین رندرهای مجدد مؤلفهتان در حافظه پنهان ذخیره کنید. کار مشابهی را انجام می دهد useMemo
، تفاوت های ظریف که در مقاله دیگری به آن خواهیم پرداخت.
اگر این موضوع به شما علاقه مند است، می توانید اطلاعات بیشتری در مورد آن در React Docs بخوانید.
لطفا به هشدار آنها توجه کنید:
- فقط باید به آن تکیه کنید
useCallback
به عنوان یک بهینه سازی عملکرد اگر کد شما بدون آن کار نمی کند، مشکل اساسی را پیدا کنید و ابتدا آن را برطرف کنید. سپس می توانید اضافه کنیدuseCallback
برای بهبود عملکرد
useCallback
نحو
useCallback
نحو بسیار شبیه به useEffect
نحو، که ما قبلا می دانیم. به اسکلت هر کدام نگاه کنید.
useEffect(() => {}, []);
useCallback(() => {}, []);
تفاوت جزئی با useEffect
، به تابع ناشناس می گوییم که تابع ما را در حین با اجرا کند useCallback
، مقدار بازگشتی را به مرجعی اختصاص می دهیم تا در جای دیگری فراخوانی شود.
ابتدا وارد می کنیم useCallback
از جانب 'react'
. به جای افزودن یک خط جدید، بهتر است آن را همراه با سایر واردات خود تخریب کنیم.
import { useState, useEffect, useCallback } from 'react';
اکنون می توانیم اختصاص دهیم getBookDetails
به مقدار بازگشتی از a useCallback
فراخوانی تابع
const getBookDetails = useCallback();
سپس تمام نحو برای را اضافه می کنیم useCallback
. آرایه وابستگی خود را به خاطر بسپارید!
const getBookDetails = useCallback(() => {}, []);
در مثال ما نیاز داریم async
قبل از پارامترهای ما
const getBookDetails = useCallback(async () => {}, []);
و در نهایت منطق تابع خود را به بلوک کد اضافه می کنیم.
const getBookDetails = useCallback(async () => {
const res = await axios.get(`${BASE_URL}/${id}`);
setBook(res.data);
console.log(res.data);
}, []);
هنگامی که ما ذخیره می کنیم، می گیریم … دیگری WARNING
.
WARNING in [eslint]
src/components/BookDetails.jsx
Line 14:6: React Hook useCallback has a missing dependency: 'id'. Either include it or remove the dependency array react-hooks/exhaustive-deps
webpack compiled with 1 warning
بیایید یک لحظه به این موضوع فکر کنیم.
چرا باید آرایه وابستگی ما ردیابی شود id
متغیر؟
اگر ارزش از
id
تغییرات، «getBookDetails» باید به نقطه پایانی دیگری برسد، بنابراین React باید آن را دوباره تعریف کند.
بعد از اینکه اضافه کردیم id
به آرایه وابستگی ما، ما تمام شده است getBookDetails
و useEffect
توابع باید شبیه این باشند. به تفاوتهای بین روش اجرای دو قلاب دقت کنید.
const getBookDetails = useCallback(async () => {
const res = await axios.get(`${BASE_URL}/${id}`);
setBook(res.data);
console.log(res.data);
}, [id]);
useEffect(() => {
getBookDetails();
}, [getBookDetails]);
و بالاخره همین! ما در سرور React dev سبز رنگ می بینیم. لینتر شاد یک توسعه دهنده ارشد خوشحال است. و یک توسعه دهنده ارشد خوشحال شما را خوشحال می کند!
من همیشه به دنبال دوستان و همکاران جدید هستم. اگر این مقاله برای شما مفید بود و میخواهید با هم ارتباط برقرار کنید، میتوانید من را در هر یک از خانههای من در وب پیدا کنید.
گیت هاب | توییتر | لینکدین | سایت اینترنتی
منابع