مقدمه
اگر در React بعد از setState یا setCount لاگ بگیرید و مقدار قبلی را ببینید، باگ نیست. React عمداً آپدیتها را غیرهمزمان و batch میکند تا رندرهای اضافه نداشته باشد. در این نوشته میبینیم چرا این اتفاق طبیعی است و چطور مقدار جدید state را درست بخوانیم.
چرا state بلافاصله عوض نمیشود؟
setStateبلافاصله مقدار را تغییر نمیدهد؛ فقط یک درخواست آپدیت در صف میگذارد.- جاوااسکریپت ادامه اجرا میشود و React بعداً در چرخهٔ رندر بعدی state جدید را اعمال میکند.
- بنابراین هر کدی که فوراً بعد از
setStateاجرا شود، هنوز به مقدار قدیمی دسترسی دارد.
فلو سادهٔ پشتصحنه:
setCountصدا زده میشود.- React آپدیت را در صف میگذارد.
- بقیهٔ کد همان لحظه اجرا میشود.
- رندر جدید انجام میشود و state تازه در دسترس قرار میگیرد.
مثال پایه
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
console.log(count); // هنوز مقدار قبلی است
};
چون console.log قبل از رندر جدید اجرا میشود، خروجی همچنان 0 است.
چطور مقدار جدید را ببینیم؟
استفاده از useEffect
useEffect(() => {
console.log(count); // همیشه مقدار بهروز
}, [count]);
useEffect بعد از رندر اجرا میشود، پس لاگ همیشه state تازه را نشان میدهد.
استفاده از Functional Update
وقتی مقدار جدید به مقدار قبلی وابسته است، فرم تابعی همیشه آخرین state را میدهد:
setCount(prev => {
const next = prev + 1;
console.log(next); // مقدار جدید همینجاست
return next;
});
چند آپدیت پشتسرهم
اشتباه رایج:
setCount(count + 1);
setCount(count + 1); // هر دو از مقدار قدیمی استفاده میکنند
نتیجه فقط +1 است. نسخهٔ درست:
setCount(prev => prev + 1);
setCount(prev => prev + 1); // مجموعاً +2
فرم تابعی تضمین میکند هر آپدیت روی تازهترین مقدار اعمال شود.
کجاها حواسمان باید باشد؟
- لاگ گرفتن بلافاصله بعد از
setState - ارسال state به API بلافاصله بعد از آپدیت
- شرطگذاری با state قدیمی (مثلاً بلافاصله در همان تابع)
- چند آپدیت متوالی روی یک state بدون فرم تابعی
در همهٔ این حالتها یا از useEffect استفاده کنید یا از functional update.
چکلیست سریع
- آیا آپدیت به مقدار قبلی وابسته است؟ → از فرم تابعی استفاده کن.
- نیاز داری مقدار بهروز را ببینی؟ → داخل
useEffectروی همان state لاگ بگیر. - چند آپدیت پشتسرهم داری؟ → همه را به صورت تابعی بنویس تا batching درست کار کند.
جمعبندی
مشاهدهٔ مقدار قدیمی بعد از setState رفتاری عمدی است، نه ایراد. React آپدیتها را صف و batch میکند؛ به همین دلیل باید یا منتظر رندر بعدی بمانید (useEffect) یا از functional update استفاده کنید تا به مقدار جدید دسترسی داشته باشید. قانون ساده: «اگر به state قبلی نیاز داری، تابعی بنویس؛ اگر میخواهی state جدید را ببینی، بعد از رندر سراغش برو.»
