React batch updates for multiple setState() calls inside useEffect hook

Nice question. Here is additional info to complete @FranklinOcean answer.

2021 update: upcoming changes in React 18

Please see Dan Abramov update concerning this topic in React 18, which is the one that adds automatic batching: https://github.com/reactwg/react-18/discussions/21

Answer for current version of react, which is 17.0.2, and below, as of 2021.

Based on the following codesandbox:


Batched setStuff calls:

  • Inline the component function block synchronously (I think it is equivalent to having an effect running before the other effects and without dependencies)
  • In a useEffect block synchronously
  • In a synthetic event handler synchronously (managed by react, such as onClick={handlerFunction})

Non batched calls that will trigger a re-render each time:

  • Any asynchronous code (promise/async function in any of the above use cases)
  • Non synthetic event (event managed outside react lib)
  • That includes XHR or other networks callbacks

I'll try re-run the sandbox with future versions of react to see how it goes!


If state updates happen directly, React will batch your updates.

Batched:

export default () => { 
   const [a, setA] = React.useState(0); 
   const [b, setB] = React.useState(0);

   useEffect(() => {
    setA(1); setB(1);
   },[]);

   return (  
    <div> 
      <p>A: {a}</p> 
      <p>B: {b}</p> 
    </div> ); 
};

Clicking this button will re-render the component only once.

Non-Batched:

export default () => { 
  const [a, setA] = React.useState(0); 
  const [b, setB] = React.useState(0);

   useEffect(() => { 
    setTimeout(() => { setA(1); setB(1); }, 1000); }
   , []);

   return ( 
    <div> 
     <p>A: {a}</p> 
     <p>B: {b}</p> 
    </div> ); 
};