useEffect
تابعی است که شما میتوانید آن را برای اجرای عملیاتی که باید به محض بروزرسانی یک کامپوننت اجرا شود استفاده کنید. با استفاده از useEffect
میتوانید با مشخص کردن یک تابع و شرطهایی که باید برای اجرای آن برقرار باشند، کدی را که به وضعیت یک کامپوننت وابسته است اجرا کنید. به عنوان مثال، شما میتوانید با استفاده از useEffect
یک درخواست API را برای دریافت دادهها ارسال کنید و آنها را در state کامپوننت ذخیره کنید. در این بخش از آموزش React به بررسی کامل این مفهوم مهم می پردازیم و تمامی جنبه های این مفهوم را بررسی می کنیم. جزئیات کامل این مفهوم را می توانید در دوره آموزش React بررسی کنید
البته، بهتر است با یک مثال ساده در ابتدا این مفهوم را بررسی کنیم. یک مثال ساده از استفاده از useEffect
برای درک بهتر عملکرد آن میتواند به این شکل باشد:
import React, { useState, useEffect } from 'react';
function Example() {
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>
);
}
در این مثال، یک state به نام count
با مقدار اولیه ۰ تعریف شده است. در تابع useEffect
، ما عنوان صفحه را به مقدار جدید count
تنظیم میکنیم. توجه کنید که تابع useEffect
بدون مقدار دوم استفاده شده است. این به این معناست که کد مربوط به useEffect
همیشه اجرا میشود، به عبارت دیگر، هر بار که مقدار count
تغییر کند، تابع useEffect
مجددا اجرا خواهد شد و عنوان صفحه بروزرسانی خواهد شد. با این مثال ساده می توانیم به جزئیات این مفهوم بپردازیم.
مفاهیم کلیدی useEffect
مفاهیم کلیدی و اساسی useEffect
در React عبارتند از:
۱. اجرا شدن useEffect
بعد از رندر شدن کامپوننت: تابع useEffect
همیشه پس از اجرای کدی که مربوط به رندر کامپوننت است اجرا میشود. بنابراین، هر تغییری در وضعیت کامپوننت (state) منجر به رندر مجدد کامپوننت و اجرای دوبارهی تابع useEffect
میشود. البته دقت کنید تعداد اجرای تابعی که در این هوک تعریف می شود قابل تنظیم است که در ادامه به این موضوع می پردازیم.
۲. تعریف یک تابع callback در useEffect
: تابع callback تعریف شده در useEffect
، کدی را اجرا میکند که وابسته به تغییراتی است که در state کامپوننت رخ میدهد. این تابع میتواند هرگونه عملیاتی را انجام دهد، از جمله درخواستهای شبکه، تغییر DOM و ... .
۳. تعریف شرطهایی برای اجرای تابع callback: میتوانید شرطهایی را برای اجرای تابع callback در useEffect
تعریف کنید. در صورتی که شرطها برقرار نباشند، تابع callback اجرا نخواهد شد. برای مثال، میتوانید شرطی برای بروزرسانی state تعریف کنید تا تابع callback اجرا شود.
۴. بازگشت یک تابع cleanup: میتوانید یک تابع cleanup در useEffect
تعریف کنید تا کدی را که باید بعد از اجرای تابع callback انجام شود تعریف کنید. این تابع به صورت دلخواه است و میتواند هرگونه عملیاتی را انجام دهد، از جمله از بین بردن یک شبکه، حذف listener و ... .
استفاده از useEffect در API کال ها
استفاده از useEffect
در asynchronous task ها به شما این امکان را میدهد که به راحتی از کدهایی که زمان زیادی برای اجرا نیاز دارند، مانند درخواست های شبکه و یا دسترسی به دیتابیس، استفاده کنید. برای این کار میتوانید از تابع async
و await
در تابع callback استفاده کنید.
به عنوان مثال، فرض کنید یک درخواست شبکه از API در کامپوننتی وجود دارد که باید در هنگام نمایش آن، از API داده بگیریم و آن را به روز کنیم. با استفاده از useEffect
میتوانیم این کار را انجام دهیم. به صورت زیر:
import { useState, useEffect } from 'react';
import axios from 'axios';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
const result = await axios.get('https://my-api.com/data');
setData(result.data);
}
fetchData();
}, []);
return (
<div>
{data ? (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
) : (
<p>Loading...</p>
)}
</div>
);
}
در این مثال، تابع fetchData
با استفاده از async
و await
از API دادهها را دریافت میکند. سپس در تابع callback از useEffect
، تابع fetchData
را فراخوانی میکنیم. با استفاده از آرگومان دوم []
، میتوانیم اطمینان حاصل کنیم که این کد تنها در هنگام اولین بار لود شدن کامپوننت اجرا میشود و برای بروزرسانیهای بعدی مجدداً اجرا نمیشود.
استفاده از useEffect
در asynchronous task ها به شما این امکان را میدهد که با استفاده از تابع async
و await
، به صورت همزمان به کدهایی که زمان زیادی برای اجرا نیاز دارند، دسترسی پیدا کنید و در کل کدهای خود را بهبود بخشید.
استفاده از چند useEffect
استفاده از چند useEffect
در یک کامپوننت، به شما امکان میدهد که به صورت مجزا برای هر عملکرد مرتبط با کامپوننت، تابع useEffect
را اجرا کنید. این کار به شما امکان میدهد که کد خود را به صورت منظم و سازماندهی شده نگه دارید و برای هر قسمت مربوط به کامپوننت، تابع useEffect
جداگانه ایجاد کنید.
به عنوان مثال، فرض کنید یک کامپوننت داریم که از دو عملکرد استفاده میکند. یکی برای دریافت داده از API و دیگری برای اعمال افکتها روی صفحه.
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function MyComponent() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const result = await axios.get('https://my-api.com/data');
setData(result.data);
setLoading(false);
}
fetchData();
}, []);
useEffect(() => {
if (!loading) {
// اعمال افکتها بر روی صفحه
}
}, [loading]);
return (
<div>
{loading ? (
<p>Loading...</p>
) : (
<ul>
{data.map((item) => (
<li key={item.id}>{item.title}</li>
))}
</ul>
)}
</div>
);
}
در این مثال، ابتدا از useEffect
برای دریافت داده از API استفاده کردیم. سپس با استفاده از useState
، یک وضعیت برای نمایش پیام "Loading..." تعریف کردیم. در useEffect
بعدی، از وضعیت loading
برای اعمال افکتها بر روی صفحه استفاده کردیم. با تغییر وضعیت loading
در تابع fetchData
، این useEffect
مجدداً فراخوانی میشود و افکتهای مربوط به صفحه را اعمال میکند.
به این ترتیب، با استفاده از چند useEffect
، میتوانید کد خود را به صورت سازماندهی شده و منظم نگه دارید.
چه زمانی useEffect اجرا می شود؟
useEffect
در کامپوننت هنگامی اجرا میشود که کامپوننت رندر میشود یا وضعیت آن تغییر میکند. برای دقیقتر بیان کردن زمانی که useEffect
اجرا میشود، میتوانیم از مفهوم "مرحله عمر کامپوننت" یا "وضعیت" استفاده کنیم.
-
رندر اولیه کامپوننت: در این مرحله،
useEffect
بلافاصله پس از رندر اولیه کامپوننت اجرا میشود. -
بهروزرسانی کامپوننت به علت تغییرات در ویژگیهای ورودی (props): اگر ویژگیهای ورودی (props) کامپوننت به روزرسانی شوند،
useEffect
پس از اعمال تغییرات و قبل از رندر مجدد کامپوننت اجرا میشود. -
بهروزرسانی کامپوننت به علت تغییر وضعیت (state) محلی: اگر وضعیت کامپوننت به دلیل تغییرات در محاسبات داخلی کامپوننت بهروزرسانی شود،
useEffect
پس از اعمال تغییرات و قبل از رندر مجدد کامپوننت اجرا میشود. -
حذف کامپوننت: در این مرحله،
useEffect
به عنوان Cleanup Function برای حذف هرگونه منبع خارجی یا عملیات پاکسازی قبل از حذف کامپوننت اجرا میشود.
با توجه به موارد فوق، میتوانیم برای هر کدام از حالات زیر، useEffect
را با یک شرط اجرا کنیم:
useEffect(() => {
// code to be executed when the component is mounted (on initial render)
}, [])
useEffect(() => {
// code to be executed when the component is updated due to changes in props
}, [prop1, prop2])
useEffect(() => {
// code to be executed when the component is updated due to changes in local state
}, [localState1, localState2])
useEffect(() => {
// code to be executed before the component is unmounted
return () => {
}
}
در واقع می توان گفت در 4 سناریو مختلف useEffect اجرا می شود:
- بارگیری اولین بار: useEffect با اجرای کامپوننت برای اولین بار اجرا میشود. به عبارت دیگر، useEffect به صورت پیشفرض هنگامی که کامپوننت لود میشود اجرا میشود.
- بروزرسانی کامپوننت: هر بار که ویژگیهای کامپوننت تغییر میکند، useEffect دوباره اجرا میشود. به عنوان مثال، هر بار که مقداری در ویژگیهای ورودی کامپوننت تغییر میکند، useEffect دوباره اجرا میشود.
- بروزرسانی ویژگیهای خاص: میتوانید useEffect را برای بروزرسانی ویژگیهای خاص کامپوننت استفاده کنید. برای این کار، میتوانید یک لیست از ویژگیها را به useEffect ارائه دهید. به عنوان مثال، اگر میخواهید useEffect فقط زمانی اجرا شود که مقداری از ویژگیهای خاص تغییر کرده باشد، میتوانید این ویژگیها را به عنوان ورودی به useEffect اضافه کنید.
- ترک کامپوننت: زمانی که کامپوننت از صفحه حذف میشود، useEffect با تابع cleanup مرتبط خود اجرا میشود. به عبارت دیگر، زمانی که کاربر از صفحه خارج میشود، تمامی منابع مصرفی کامپوننت (مانند شبکه، سیستم فایل، حافظه و ...) آزاد شده و cleanup function اجرا میشود.
تعیین زمان اجرا تابع با استفاده از Dependency Array
همانطور که گفته شد Dependency array در useEffect شامل مقادیری است که تغییر آنها باعث اجرای دوباره callback function در useEffect میشود. برخی از انواع معمول dependency array عبارتند از:
1- Dependency array خالی: اگر dependency array خالی باشد، callback function در useEffect فقط یکبار اجرا میشود و در صورت تغییر هیچ dependency ای، دوباره اجرا نمیشود.
مثال:
useEffect(() => {
console.log("Component mounted");
}, []);
2- Dependency array با وجود یک مقدار: اگر مقداری در dependency array وجود داشته باشد، callback function در useEffect زمانی اجرا میشود که آن مقدار تغییر کند.
مثال:
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count changed to ${count}`);
}, [count]);
3- Dependency array با وجود چند مقدار: اگر چندین مقدار در dependency array وجود داشته باشد، callback function در useEffect زمانی اجرا میشود که هر یک از آنها تغییر کند.
مثال:
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
useEffect(() => {
console.log(`Full name changed to ${firstName} ${lastName}`);
}, [firstName, lastName]);
4- Dependency array با عدم وجود آن: اگر هیچ dependency arrayی در useEffect وجود نداشته باشد، callback function هر بار که هر کدام از متغیرهای state در component تغییر کند، دوباره اجرا میشود.
مثال:
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
useEffect(() => {
console.log(`Full name changed to ${firstName} ${lastName}`);
});
// برای تغییر stateها مقدار زیر را به کار ببرید
// setFirstName("John");
// setLastName("Doe");
5- Dependency array با استفاده از مقداری به نام previous state: میتوانید از مقداری به نام previous state استفاده کنید تا بتوانید تغییرات مقدار state را مقایسه کنید و در صورت تغییرات مورد نیاز، callback function را اجرا کنید.
مثال:
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count changed from ${prevState.count} to ${count}`);
}, [count]);
به طور کلی dependency array میتواند ترکیبی از انواع مختلفی باشد که بسته به نیاز پروژه و متغیرهایی که در component استفاده میشوند، تنظیم میشوند. در نهایت، تنظیم درست dependency array در useEffect میتواند به بهینهتر کردن عملکرد component و کاهش تعداد re-renderهای غیر ضروری در React کمک کند.
Cleanup Function چیست و چه کاربردی دارد؟
Cleanup function یک تابع است که در useEffect تعریف می شود و وظیفه آن پاکسازی و رفع اثرات کنونی کامپوننت است. این تابع هنگامی فراخوانی می شود که کامپوننت غیرفعال شود یا به روزرسانی شود و یا کامپوننت از DOM حذف شود.
مثال:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component did mount or update');
// cleanup function
return () => {
console.log('Component will unmount or update');
}
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
در این مثال، useEffect یک callback function دریافت می کند و هر بار که کامپوننت mount یا update می شود، این callback function فراخوانی می شود. همچنین، useEffect یک تابع cleanup دارد که هر بار که کامپوننت unmount یا update می شود، این تابع فراخوانی می شود و اثرات کامپوننت را پاکسازی می کند.
چه زمانی از useEffect استفاده نکنیم؟
استفاده از useEffect باید با دقت و با توجه به نیازهای پروژه صورت گیرد. در برخی موارد، استفاده از useEffect ممکن است بیش از حد زیاد شده و اثرات منفی بر روی عملکرد کلی اپلیکیشن داشته باشد. در زیر مواردی را که میتوان از استفاده از useEffect خودداری کرد، بررسی میکنیم:
-
در صورتی که قرار نیست در حین بارگیری صفحه دادههای دیگری از سرور دریافت کنیم، مانند صفحههای استاتیک، نیازی به استفاده از useEffect نیست.
-
در صورتی که نیازی به اجرای یک کد در هنگام بروزرسانی UI نباشد، مثلا اگر اجزای UI شما به صورت دائمی در حال نمایش داده شدن هستند، نیازی به استفاده از useEffect نیست.
-
در صورتی که اجرای کدی که درون useEffect قرار دارد، زمان زیادی نمیبرد و از منابع سنگینی استفاده نمیکند، میتوان آن را در قسمت مربوطه، مثلا در هنگام رندر کامپوننت، اجرا کرد.
-
در صورتی که کدی که درون useEffect قرار دارد، در هر بار رندر کامپوننت، نیازی به اجرا ندارد، بلکه فقط در زمان بارگیری صفحه اجرا شود، میتوان از useEffect استفاده کرد، اما حتماً باید dependency array آن را خالی گذاشت تا فقط در اولین بار بارگیری صفحه اجرا شود.
به طور کلی، استفاده از useEffect باید با توجه به نیازهای پروژه و در مواردی که واقعاً نیاز به اجرای کد در هنگام بروزرسانی UI وجود دارد، صورت گیرد.
خلاصه
useEffect یک Hook در React است که به شما امکان می دهد به راحتی با چرخه عمر کامپوننت ها در React کار کنید. این Hook مجموعه ای از توابع را در اختیار شما قرار می دهد تا بتوانید با تغییرات مرتبط با اجرای کامپوننت خود، کد خود را به روز کنید.
استفاده از useEffect در کامپوننت ها به شما این امکان را می دهد که به راحتی با محتوایی که به سایت یا برنامه شما بارگذاری شده است، کار کنید. همچنین می توانید با استفاده از useEffect بر روی داده هایی که برای کاربر باید به روز شوند، کنترل داشته باشید.
در کل، استفاده از useEffect به شما این امکان را می دهد که با تغییرات مرتبط با اجرای کامپوننت خود، کد خود را به روز کنید و بتوانید به راحتی با محتوایی که به سایت یا برنامه شما بارگذاری شده است، کار کنید.
برای جزئیات بیشتر این مفهوم می توانید دوره جامع آموزش React را بررسی و در این دوره شرکت کنید