react-use-batched-state

React hook similar to `setState` but allowing for batched updates

Usage no npm install needed!

<script type="module">
  import reactUseBatchedState from 'https://cdn.skypack.dev/react-use-batched-state';
</script>

README

react-use-batched-state

A hook that allows for batched updates in react.

Install

npm i react-use-batched-state

There are umd and es versions if you need.

Usage

Use it instead of React.useState wherever you need to batch updates (see the example). Typescript support is available. This package requires Promise to be available globally, it is not bundled as it's very much likely you already have one.

Motivation

In certain cases (generally, in effects) state updates initiated by React.useState setters are not batched, which leads to rerender for each setter call. Consider the following example:

import React, { useState, useCallback } from 'react';

export default function BatchedUpdateTest() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);

  console.log(`render: a = ${a}, b = ${b}`);

  const setUpdate = useCallback(function setUpdate() {
    setTimeout(
      function (x) {
        setA(x);
        setB(x)
      },
      500,
      Math.random()
    );
  }, []);

  return (
    <button onClick={setUpdate}>set update</button>
  );
}

If we click on the button, we will see the console prints next two lines:

render: a = 0.8447694095332172, b = 0
render: a = 0.8447694095332172, b = 0.8447694095332172

Solution

react-use-batched-state supposed to solve the problem. You can use it in place of React.useState wherever you want updates to batch:

import React, { useCallback } from 'react';
import useBatchedState from 'react-use-batched-state';

export default function BatchedUpdateTest() {
  const [a, setA] = useBatchedState(0);
  const [b, setB] = useBatchedState(0);

  console.log(`render: a = ${a}, b = ${b}`);

  const setUpdate = useCallback(function setUpdate() {
    setTimeout(
      function (x) {
        setA(x);
        setB(x)
      },
      500,
      Math.random()
    );
  }, []);

  return (
    <button onClick={setUpdate}>set update</button>
  );
}

If we click the button now, the output would be

render: a = 0.8447694095332172, b = 0.8447694095332172

How it works

Internally it uses unstable_batchedUpdates from react-dom (which is not so unstable).

Requirements

This package requires Promise to be available globally, it is not bundled as it's very much likely you already have one.