Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does React batch state update functions when using hooks?

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?

like image 484
vadirn Avatar asked Oct 29 '18 15:10

vadirn


People also ask

Does React batch state updates?

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.

How do you update state in React hooks?

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) .

Do hooks share state between components?

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.


1 Answers

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.

like image 68
Patrick Hund Avatar answered Sep 28 '22 04:09

Patrick Hund