For class components, this.setState
calls batch if inside event handlers. But what happens if state is updated outside the event handler and using useState
hook?
function Component() { const [a, setA] = useState('a'); const [b, setB] = useState('b'); function handleClick() { Promise.resolve().then(() => { setA('aa'); setB('bb'); }); } return <button onClick={handleClick}>{a}-{b}</button> }
Will it render aa - bb
right away? Or it will be aa - b
and then aa - bb
?
React uses batching to group state updates within event handlers and inbuilt hooks. It prevents components from re-rendering for each state update and improves application performance. React 17, and prior versions only support batching for browser events.
To update the state, call the state updater function with the new state setState(newState) . Alternatively, if you need to update the state based on the previous state, supply a callback function setState(prevState => newState) .
If you are referring to component state, then hooks will not help you share it between components. Component state is local to the component. If your state lives in context, then useContext hook would be helpful.
TL;DR – if the state changes are triggered asynchronously (e.g. wrapped in a promise), they will not be batched; if they are triggered directly, they will be batched.
I've set up a sandbox to try this out: https://codesandbox.io/s/402pn5l989
import React, { Fragment, useState } from 'react'; import ReactDOM from 'react-dom'; import './styles.css'; function Component() { const [a, setA] = useState('a'); const [b, setB] = useState('b'); console.log('a', a); console.log('b', b); function handleClickWithPromise() { Promise.resolve().then(() => { setA('aa'); setB('bb'); }); } function handleClickWithoutPromise() { setA('aa'); setB('bb'); } return ( <Fragment> <button onClick={handleClickWithPromise}> {a}-{b} with promise </button> <button onClick={handleClickWithoutPromise}> {a}-{b} without promise </button> </Fragment> ); } function App() { return <Component />; } const rootElement = document.getElementById('root'); ReactDOM.render(<App />, rootElement);
I've made two buttons, one triggers the state changes wrapped in a promise like in your code example, the other triggers the state changes directly.
If you look at the console, when you hit the button “with promise”, it will first show a aa
and b b
, then a aa
and b bb
.
So the answer is no, in this case, it will not render aa - bb
right away, each state change triggers a new render, there is no batching.
However, when you click the button “without promise”, the console will show a aa
and b bb
right away.
So in this case, React does batch the state changes and does one render for both together.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With