After some trial I discovered following problem occurs in strict mode. I would be interested if someone can explain why.
Take this simple example where inside render I am just scheduling a timeout which updates state:
let firstRender = true; // Normally I would use ref but I was playing with example
export default function App() {
let [data, setData] = React.useState({ name: 'Nick' });
// Schedule a timeout on first render
if (firstRender) {
setTimeout(() => {
console.log('Running');
setData((ps) => ({
...ps,
name: 'Paul',
}));
}, 1000);
}
console.log('Running render');
firstRender = false;
return (
<div>
<h1>{data.name}</h1>
<p>Start editing to see some magic happen :)</p>
</div>
);
}
If you run this example without Strict mode, then you will see "Paul" on screen after one second, as I was expecting.
If you use Strict mode, it will always show "Nick" on screen. Idea why?
Note: it seems using useRef instead of the global variable firstRender fixes this problem also in Strict mode. This seems to happen because ref was set in first render, and its value also got discarded (see also the answer).