هنگامی که فرد تصمیم می گیرد با یادگیری React به جلو حرکت کند، هوک ها جزو اولین چیزهایی هستند که باید یاد بگیرند (و از آنها ناامید شوند). هوکها بخشهای ضروری React هستند، زیرا برای حل چندین مشکل ایجاد شدهاند که در دو نسخه اول React ظاهر میشوند، زمانی که هر رندر در داخل توابع چرخه حیات کامپوننت انجام میشود، مانند ()componentDidMount()
، componentWillMout()
، componentDidUpdate
.
همانطور که گفته شد، اولین هوک هایی که همه شروع به استفاده کردن می کنند، ()useState
و ()useEffect
. اولین مورد برای مدیریت و کنترل استیت ها زمانی که کامپوننت باید دوباره رندر شود استفاده می شود، در حالی که دومی تا حدودی مشابه توابع چرخه عمر ذکر شده در بالا عمل می کند.
هوک useEffect در React چیست؟
useEffect در ReactJS برای مدیریت side effects مانند واکشی داده ها و به روز رسانی DOM استفاده می شود. این هوک روی هر رندر اجرا می شود اما راهی برای استفاده از آرایه وابستگی نیز وجود دارد که با استفاده از آن می توانیم اثر رندر را کنترل کنیم.
هوک ()useEffect
می تواند دو خروجی دریافت کند: اولی تابع فراخوانی است، در حالی که دومی اختیاری است و تعیین می کند که این هوک چه زمانی باید فراخوانی شود.
useEffect((prevProps) => {
//prevProps are optional and has some specific uses. Compare with what happens with the lifecycle functions.
//Custom function content….
custom function content…
return () => {
// Code to run when the component is unmounted or when dependencies change
// It helps in avoiding memory leaks and unexpected behavior
};
}, [dependencies in array form]);
یکی از نکاتی که افراد مبتدی زیادی را جذب می کند نحوه عملکرد پارامتر دوم است :
مورد A: اگر چیزی اضافه نشود،
useEffect
در هر تغییر استیت در کامپوننت فعلی اجرا می شود.استیت B: اگر یک آرایه خالی اضافه شود (
[]
)، پس از نصب کامپوننت،useEffect
تنها یک بار اجرا می شود.مورد C: اگر مقداری آرایه (
[state]
) ارائه شود، هر بار که استیت تغییر کندuseEffect
اجرا میشود.مورد C*: اگر مقداری آرایه ارائه شود ([
state1, state2,….
]، useEffect هر بار که هر یک از این استیت ها تغییر کند اجرا می شود.
اکنون که نحوه عملکرد useEffect را دوباره بررسی کردیم، ضروری است که در تکنیک بهینهسازی به نام حافظهسازی بپردازیم. حافظهگذاری به جلوگیری از رندرهای غیرضروری کمک میکند و میتواند عملکرد کامپوننتهای شما را بهطور قابل توجهی افزایش دهد، بهویژه زمانی که با آرایههای وابستگی در useEffect
سروکار دارید.
چرا هوک useEffect را انتخاب کنید؟
هوک useEffect برای کنترل ساید افکت در کامپوننت های فانشکنال، مانند واکشی داده ها، به روز رسانی DOM، و تنظیم اشتراک ها یا تایمرها استفاده می شود. برای تقلید از متد های چرخه حیات اجزای کلاس محور استفاده می شود. انگیزه معرفی هوک useEffect حذف ساید افکت استفاده از کامپوننت های کلاس محور است. به عنوان مثال، کارهایی مانند بهروزرسانی DOM، واکشی دادهها از نقاط پایانی API، تنظیم اشتراکها یا تایمرها و غیره میتوانند منجر به ساید افکت غیرقابل توجیه شوند. از آنجایی که متد رندر برای ایجاد یک باگ بسیار سریع است، برای مشاهده ساید افکت ها باید از مت های چرخه عمر استفاده کرد.
هوک useEffect چگونه کار می کند؟
شما useEffect را با یک تابع callback که حاوی منطق ساید افکت است فراخوانی می کنید.
به طور پیش فرض، این تابع پس از هر رندر کامپوننت اجرا می شود.
شما می توانید به صورت اختیاری یک آرایه وابستگی به عنوان آرگومان دوم ارائه دهید.
این افکت تنها در صورتی دوباره اجرا می شود که هر یک از مقادیر آرایه وابستگی تغییر کند.
ایده اصلی هوک useEffect همگام سازی انتقال داده با API های خارجی یا سیستم دیگری است، مانند زمانی که به یک پایگاه داده دسترسی دارید یا منتظر تکمیل درخواست HTTP هستید. مشکل اینجاست که ما تمایل داریم از این هوک در هر موقعیت ممکن در داخل کدمان استفاده کنیم، به خصوص موارد A و C* که در بالا ذکر شده است، و کد می تواند به طور باورنکردنی با چند خط کد غیرقابل خواندن شود، از جمله راه اندازی یک حلقه در صورت تغییر یکی از استیت های موجود در آرایه وابستگی در طول فرآیند.
این میتواند کد شما را نیز ناکارآمد کند، زیرا useEffect طوری کار میکند که انگار برای اجرای کد کنار میروید و سپس به رشته اصلی باز میگردید. این می تواند کارآمدتر باشد.
عالی، اکنون می دانید که گاهی اوقات، useEffect بهترین راه حل نیست. اکنون هر مورد را به تفصیل بررسی خواهیم کرد.
برای آشنایی با کد نویسی تمیز در ری اکت می توانید این مقاله را بررسی کنید.
چه زمانی نباید از هوک useMemo استفاده کنیم؟
اشتباهات در استفاده از useEffect؟
بهعنوان توسعهدهندگان react، همه ما بارها و بارها با useEffect کار کردهایم، اما آیا تا به حال به این فکر کردهایم که useEffect چیست، چه کاری انجام میدهد و آیا واقعاً از useEffect به درستی استفاده میکنیم یا شاید از آن سوء استفاده نمیکنیم؟ شاید ما از useEffect به درستی در جای درست استفاده نمیکنیم، باید از آن استفاده کنیم زیرا همانطور که همه ما میدانیم تقریباً برای همه چیز به عنوان React Developers برای واکشی دادهها، مدیریت رویدادها، تبدیل دادهها، اجزای بزرگ یا حتی پیادهسازی منطق پیشرفته از آن استفاده میکنیم.
اگر به داکیومنت React جدید بروید که کاملاً یک بازنویسی از اسناد قدیمی react است و به دنبال هوک useEffect بگردید، می گوید
"useEffect یک هوک React است که به شما امکان می دهد یک کامپوننت را با یک سیستم خارجی همگام سازی کنید."
بنابراین از این منظر، به این معنی است که برای همگام سازی است نه برای مدیریت رویدادها یا تبدیل داده ها. این فقط برای همگام سازی با یک کامپوننت خارجی استفاده می شود.
منظور از synchronicization این است که useEffects به منظور مشخص کردن ساید افکت است که به جای یک رویداد خاص، ناشی از رندر کردن خود است.
ری اکت 19 معرفی شد برای آشنایی با ویژگی های آن این مقاله را بررسی کنید و همچنین برای آشنایی با تفاوت های آن با ری اکت 18 نیز این مقاله را مطالعه کنید.
اشتباهات رایج در هوک useEffect
بیایید در مورد هر یک از موارد استفاده با جزئیات صحبت کنیم:
مورد A - بدون آرایه وابستگی: این یکی باید از کد شما حذف شود، زیرا مطمئناً هر بار که یک استیت تغییر می کند محاسبات غیر ضروری را آغاز می کند. در این مورد، باید مشخص کنید که کدام استیت ها باید این تابع را با استفاده از یک آرایه وابستگی فعال کنند.
مورد B - آرایه وابستگی خالی: این یکی از موارد خوب است، تنها توصیهای که میتوانم ارائه کنم این است که فقط یکی از آنها را برای هر کامپوننت نگه دارم و محتوای آن را در یک تابع قرار دهم.
مورد ج - فقط یک استیت وابستگی: اگر در حال پردازش داده های خارجی هستید، استفاده از آن اشکالی ندارد. در غیر این صورت، باید آن را به راه حلی که در زیر ارائه خواهم داد تغییر دهید.
مورد C* - چندین استیت وابستگی در یک useEffect: این موردی است که به نظر من دردسرسازترین است. توصیه میکنم قبل از هر کاری، استیتها را در هوکهای useEffect مختلف باز کنید، زیرا باعث میشود کد شما بسیار ناخوانا باشد.
حالا راه حلی که قول داده بودم. بیایید این دو کامپوننت (والد و فرزند) را در نظر بگیریم:
// ParentComponent.js
import React, { useState, useEffect } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('Hello from Parent!');
useEffect(() => {
setMessage(`Button clicked ${count} times!`);
},[count]}
return (
<ChildComponent count={count} message={message} setCount={setCount} />
);
}
export default ParentComponent;
// ChildComponent.js
import React from 'react';
function ChildComponent({ count, message, setCount }) {
return (
<div>
<h3>Child Component</h3>
<p>Received Count from Parent: {count}</p>
<p>Received Message from Parent: {message}</p>
<button onClick={() => {setCount(count+1)}>Click Me</button>
</div>
);
}
export default ChildComponent;
حالا بیایید توضیح دهیم که اینجا چه اتفاقی می افتد:
1 - هنگامی که کاربر روی دکمه ChildComponent
کلیک می کند، وضعیت "count" را با افزایش 1 تغییر می دهیم. یک حلقه رندر طول می کشد تا اتفاق بیفتد و استیت تغییر کند.
2- هنگامی که استیت "count" تغییر کرد، کامپوننت فرزند دوباره رندر می شود و همچنین هوک useEffect
را در هر دو کامپوننت فعال می کند که باعث تغییر در استیت «message
» می شود. باز هم فقط در رندر بعدی اتفاق می افتد.
3- هنگامی که استیت "message
" تغییر می کند، رندر دیگری در اجزای تغییر message
اتفاق می افتد.
در این مورد، ما در نهایت دو رندر داشتیم. اکنون ممکن است زیاد به نظر برسد، اما زمانی که استیت های بیشتری در بازی داشته باشید، می تواند در مقیاس بزرگ رشد کند.
حالا ببینید وقتی تغییرات زیر را در کامپوننت ها ایجاد می کنیم چه اتفاقی می افتد:
// ParentComponent.js
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState('Hello from Parent!');
const incrementCount = () => {
setCount(count + 1);
setMessage(`Button clicked ${count + 1} times!`);
}
return (
<ChildComponent count={count} message={message}
callbackFunction={incrementCount} />
);
}
export default ParentComponent;
// ChildComponent.js
import React from 'react';
function ChildComponent({ count, message, callbackFunction }) {
return (
<div>
<h3>Child Component</h3>
<p>Received Count from Parent: {count}</p>
<p>Received Message from Parent: {message}</p>
<button onClick={callbackFunction}>Click Me</button>
</div>
);
}
export default ChildComponent;
ما کد را تغییر دادیم تا یک callbackFunction
به کامپوننت فرزند ارسال شود. ممکن است متوجه شوید که:
ما دیگر یک useEffect بر روی کامپوننت والد تعریف نشده ایم. این کار خواندن کد را آسانتر میکند، زیرا میتوانیم کد خود را به عنوان مثال خطیتر و تک رشتهایتر از کد اصلی درک کنیم.
لازم نیست منتظر دو چرخه رندر برای نمایش پیام نهایی خود باشیم، یا بدتر از آن، هر دو کامپوننت را دو بار رندر کنیم.
میتوانیم نگرانیها را بین کامپوننتها تفکیک کنیم، و آنها را قابل استفادهتر کنیم و خواندن یا تطبیق آنها را آسانتر کنیم، زیرا میتوانیم هر آنچه را که میخواهیم در تابع callback قرار دهیم.
هر دو استیت به طور همزمان تغییر می کنند و از زنجیره ای شدن عبارات useEffect اجتناب می کنند.
برای پیاده سازی میکرو فرانت اند با ری اکت این مقاله را از دست ندهید.
استیت های خود را با ریداکس مدیریت کنید برای آشنایی با ریداکس این مقاله را بررسی کنید.
با استفاده از گراف کیوال و ری اکت اپلکیشن های قدرتمندی بسازید.
نتیجه
در پایان، بینش های ارائه شده در اینجا راهنمایی های ارزشمندی را ارائه می دهند، اما مهم است که بدانیم توسعه نرم افزار یک زمینه پویا است و راه حل ها برای همه یکسان نیستند. useEffect بخش بسیار مهمی از React است، اما گاهی اوقات بهترین راه حل نیست.