مدیریت اثرات جانبی با useEffect در React
در برنامههای React، برخی عملیات مانند درخواستهای API، کار با localStorage، تغییر عنوان صفحه، تایمرها و تعامل با DOM را نمیتوان مستقیماً در بدنه کامپوننت انجام داد. برای مدیریت این اثرات جانبی (Side Effects) از هوک useEffect استفاده میکنیم.
۱. useEffect چیست و چرا مهم است؟
useEffect یک هوک React است که اجازه میدهد عملیات جانبی را در کامپوننتهای فانکشنی مدیریت کنیم. این هوک جایگزین متدهای componentDidMount، componentDidUpdate و componentWillUnmount در کامپوننتهای کلاسی شده است.
ساختار کلی useEffect
// کد مربوط به اثر جانبی
return () => {
// کد پاکسازی (اختیاری)
};
}, [dependencies]);
✔ اثر جانبی اجرا میشود: وقتی کامپوننت لود یا بهروزرسانی شود.
✔ پاکسازی انجام میشود: هنگام حذف کامپوننت یا تغییر مقدار در dependencies.
✔ کنترل اجرا با dependencies: مشخص میکند که useEffect چه زمانی اجرا شود.
۲. اجرای useEffect در هر رندر
اگر useEffect بدون آرایه وابستگی باشد، در هر بار رندر شدن کامپوننت اجرا خواهد شد.
مثال: نمایش پیام در Console در هر رندر
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("کامپوننت رندر شد!");
});
return (
<div>
<h1>عدد: {count}</h1>
<button onClick={() => setCount(count + 1)}>افزایش</button>
</div>
);
};
export default Counter;
✅ در این مثال، console.log در هر بار تغییر count اجرا میشود.
✅ از آنجا که useEffect بدون آرایه وابستگی است، در هر رندر اجرا خواهد شد.
۳. اجرای useEffect فقط هنگام mount (بارگذاری اولیه)
اگر بخواهیم useEffect فقط یکبار، هنگام لود شدن کامپوننت اجرا شود، باید آرایه وابستگیها را خالی [ ] بگذاریم.
مثال: درخواست API فقط هنگام لود شدن
const Users = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
.then(data => setUsers(data));
}, []); // آرایه خالی یعنی فقط یکبار اجرا شود.
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default Users;
✅ useEffect فقط یکبار اجرا میشود، چون آرایه وابستگی خالی [ ] است.
۴. اجرای useEffect هنگام تغییر مقدار خاص
میتوان مشخص کرد که useEffect فقط هنگام تغییر مقدار خاصی اجرا شود.
مثال: اجرای useEffect فقط هنگام تغییر count
console.log(`مقدار count تغییر کرد: ${count}`);
}, [count]); // فقط وقتی count تغییر کند اجرا میشود.
✅ اگر count تغییر کند، useEffect اجرا میشود.
✅ اگر مقدار دیگری (مثلاً یک ورودی متن) تغییر کند، useEffect اجرا نخواهد شد.
۵. پاکسازی (Cleanup) در useEffect
در برخی موارد، هنگام حذف کامپوننت باید تایمرها، لیسنرها یا درخواستهای API را متوقف کنیم تا از مشکلات حافظه (Memory Leak) جلوگیری شود. این کار را در تابع بازگشتی useEffect انجام میدهیم.
مثال: مدیریت تایمر با useEffect
const Timer = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);
return () => {
clearInterval(interval); // پاکسازی تایمر هنگام حذف کامپوننت
};
}, []);
return <h1>زمان: {seconds} ثانیه</h1>;
};
export default Timer;
✅ در این مثال، تایمر هر ۱ ثانیه مقدار seconds را افزایش میدهد.
✅ هنگام حذف کامپوننت، clearInterval(interval) تایمر را متوقف میکند تا از مشکلات حافظه (Memory Leak) جلوگیری شود.
۶. چندین useEffect در یک کامپوننت
میتوان چندین useEffect در یک کامپوننت داشت، هر کدام برای کارهای مختلف.
مثال: یکی برای درخواست API و دیگری برای تغییر عنوان صفحه
const Profile = () => {
const [user, setUser] = useState(null);
const [count, setCount] = useState(0);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => response.json())
.then(data => setUser(data));
}, []);
useEffect(() => {
document.title = `شمارنده: ${count}`;
}, [count]);
return (
<div>
{user ? <h2>نام: {user.name}</h2> : <p>در حال بارگذاری...</p>}
<button onClick={() => setCount(count + 1)}>افزایش</button>
</div>
);
};
export default Profile;
✅ useEffect اول فقط هنگام لود شدن اجرا شده و دادههای کاربر را دریافت میکند.
✅ useEffect دوم فقط هنگام تغییر count اجرا شده و عنوان صفحه را تغییر میدهد.
جمعبندی و نکات مهم
✅ useEffect برای مدیریت اثرات جانبی (Side Effects) مانند درخواست API، تایمرها و تغییرات DOM استفاده میشود.
✅ بدون آرایه وابستگی، useEffect در هر رندر اجرا میشود.
✅ با آرایه خالی [ ] فقط یکبار هنگام mount اجرا میشود.
✅ با آرایه [dependency] فقط وقتی مقدار آن تغییر کند، اجرا میشود.
✅ برای جلوگیری از مشکلات حافظه (Memory Leak)، باید در useEffect پاکسازی (Cleanup) انجام دهیم.
✅ میتوان چندین useEffect در یک کامپوننت داشت.