DEV Community

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

Posted on • Edited 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.

For a much more extensive guide on getting the most out of React portals, check out my full 24-page PDF file on Gumroad. It's available for just $10:

Using React Portals Like a Pro.

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

AWS Security LIVE! Stream

Go beyond the firewall

Watch AWS Security LIVE! to uncover how today’s cybersecurity teams secure what matters most.

Learn More

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

Image of Quadratic

Free AI chart generator

Upload data, describe your vision, and get Python-powered, AI-generated charts instantly.

Try Quadratic free

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay