𝗘𝘀𝗰𝗮𝗽𝗶𝗻𝗴 𝘁𝗵𝗲 𝗧𝗿𝗮𝗽: 𝗙𝗶𝘅𝗶𝗻𝗴 𝗦𝘁𝗮𝗹𝗲 𝗖𝗹𝗼𝘀𝘂𝗿𝗲𝘀 𝗶𝗻 𝗥𝗲𝗮𝗰𝘁 𝗛𝗼𝗼𝗸𝘀
Stale closures cause silent data loss in React.
You build a dashboard with a background timer. You use setInterval inside a useEffect hook to auto-save data every 5 seconds.
The bug happens when the interval fires. It saves an empty document even if the user typed a full page. The interval stays stuck in the past. It uses an old version of your state.
The Problem
When useEffect runs, it captures the variables in its scope.
- If you leave the state out of the dependency array, the interval uses the state from the first render.
- If you add the state to the dependency array, React restarts the interval on every keystroke. This kills performance and breaks your timing.
The Solution: The Mutable Ref Pattern
You must separate the timer from the data. Use the useRef hook to keep a constant reference to your latest state. This avoids re-renders and keeps your interval stable.
How to implement it:
- Create a ref to hold your latest state.
- Use a useEffect to update that ref whenever your state changes.
- Start your interval with an empty dependency array so it runs only once.
- Access the ref inside your interval callback.
This method ensures your background tasks always use fresh data. It keeps your UI fast and your data safe.
Source: https://dev.to/iprajapatiparesh/escaping-the-trap-fixing-stale-closures-in-react-hooks-4gg7