DEV Community

Cover image for How to Build a React Hook That Batches Multiple State Updates Automatically
HexShift
HexShift

Posted on

How to Build a React Hook That Batches Multiple State Updates Automatically

React already batches updates inside event handlers, but outside of those — like in setTimeout or Promise callbacks — you might hit multiple renders. Here’s how to create a custom hook that forces batching everywhere, minimizing re-renders and saving performance without needing external libraries like Recoil or Jotai.

Why Manual Batching Matters

Use cases where batching helps:

  • Complex forms with many fields updated in sequence
  • Animations or state transitions tied to promises or timers
  • Micro-optimizing deeply nested component trees

Step 1: Create a useBatchState Hook

// useBatchState.js
import { useState, useRef } from "react";
import { unstable_batchedUpdates } from "react-dom"; // Works in React 18+

export function useBatchState(initialState) {
  const [state, setState] = useState(initialState);
  const pending = useRef([]);

  function batchUpdate(updater) {
    pending.current.push(updater);
  }

  function flush() {
    if (pending.current.length === 0) return;
    unstable_batchedUpdates(() => {
      setState(prev => {
        return pending.current.reduce((acc, fn) => fn(acc), prev);
      });
    });
    pending.current = [];
  }

  return [state, batchUpdate, flush];
}

Step 2: Using the Hook

// ExampleComponent.js
import { useBatchState } from "./useBatchState";

function ExampleComponent() {
  const [count, batchUpdate, flush] = useBatchState(0);

  function complexIncrement() {
    batchUpdate(prev => prev + 1);
    batchUpdate(prev => prev + 1);
    batchUpdate(prev => prev + 1);
    flush(); // Forces all updates to apply at once
  }

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={complexIncrement}>Increment by 3</button>
    </div>
  );
}

export default ExampleComponent;

Step 3: Notes on React 18+

React 18 batches most things by default, but custom hooks like this still give you absolute control for rare cases or legacy codebases that need it.

Pros and Cons

✅ Pros

  • Fewer renders = faster UI for complex state interactions
  • No external dependencies
  • Works across async event boundaries

⚠️ Cons

  • Manual flushing required — if you forget it, you'll have stale updates
  • Can overcomplicate simple cases — don't overuse unless profiling says it's needed

🚀 Alternatives

  • React 18 automatic batching: Works out of the box for most cases, but not 100% for all async flows.
  • State libraries like Jotai, Recoil: Handle fine-grained state natively with batched atoms/selectors.

Summary

Smart batching gives you superpowers when optimizing performance-critical components. Use it when profiling shows wasteful renders — not just because you can.

If you found this useful, you can support me here: buymeacoffee.com/hexshift

Top comments (1)

Collapse
 
jamesdayal99 profile image
James

Can you accept my invitation so that I can get a free gift?
temu.com/u/XtD2852IPG47cIB
The person who will install and login with this Referral link can buy anything here free