Reputation: 31335
From React DOCS:
https://reactjs.org/docs/state-and-lifecycle.html
State Updates May Be Asynchronous
React may batch multiple setState() calls into a single update for performance.
This makes total sense. If you have something like the function below, it would be very inefficient to re-render on every setState
call
const [state1,setState1] = useState(false);
const [state2,setState2] = useState(false);
const [state3,setState3] = useState(false);
function handleClick() {
setState1(true);
setState2(true);
setState3(true);
}
So, in the situation above, I expect React to batch all 3 setState
calls into a single re-render. And it does exactly that!
But what I want to know is:
Once handleClick
has completed, is a re-render guaranteed to happen immediatelly handleClick
has done running? I mean literally immediately, like synchronously immediately?
From this snippet that I've build, it seems that this is true. React will synchronously apply the updates (re-render) after handleClick
has completed. Correct me if I'm wrong in assuming that.
See snippet below:
handleClick
will call a setState
and will log the current props.counter
App
, so it will take a long time to re-renderprops.counter
is different every time, without any repetition, even if you click multiple times really fasthandleClick
function has already been recreated with the new value for props.counter
that came from the counter
updated state.QUESTION
When setState
calls are made inside an event handler function, once that handler function has completed running, is it guaranteed that a re-render will occur immediately (synchronously) after that completion of the handler?
function App() {
console.log("App rendering...");
const [counter, setCounter] = React.useState(0);
// AN EXPENSIVE LOOP TO SLOW DOWN THE RENDER OF 'App'
for (let i = 0; i < 100000; ) {
for (let j = 0; j < 10000; j++) {}
i = i + 1;
}
return <Child counter={counter} setCounter={setCounter} />;
}
function Child(props) {
console.log("Child rendering...");
// THIS FUNCTION WILL CALL 'setState'
// AND WILL ALSO LOG THE CURRENT 'props.counter'
function handleClick() {
props.setCounter(prevState => prevState + 1);
console.log(props.counter);
}
return (
<React.Fragment>
<div>Counter: {props.counter}</div>
<button onClick={handleClick}>Click</button>
</React.Fragment>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
Upvotes: 7
Views: 1999
Reputation: 1074138
Once
handleClick
has completed, is a re-render guaranteed to happen immediatellyhandleClick
has done running? I mean literally immediately, like synchronously immediately
For certain events, including click
, React guarantees that the component will be re-rendered before another event can occur. (This isn't the case for other events like mousemove
.) You can find which events are which here. The current terminology seems to be that DiscreteEvent
s are the ones for which this guarantee exists, and the UserBlockingEvent
s are the ones for which it isn't guaranteed. It may well be that in the current implementation that means it's done synchronously at the end of the event handling¹, but I think the guarantee is less specific than that.
I learned this from Dan Abramov on Twitter (he used the older terminology for the events).
¹ Edit: and in fact, in his answer Joseph D. points to a comment by Dan Abramov saying that it is, for now, but also saying "This is implementation detail and may change in future versions".
Upvotes: 10
Reputation: 12174
is it guaranteed that a re-render will occur immediately (synchronously) after that completion of the handler?
Yes for onClick
.
React batches all setStates done during a React event handler, and applies them just before exiting its own browser event handler.
Upvotes: 4