In this article, we will look into the use of ReactDOM.unstable_batchedUpdates within a test case, specifically in Zustand, a popular state management library for React. We'll also break down the test and explain how batched updates enhance performance in React by minimizing unnecessary re-renders.
Here is the test case we’ll be examining:
This test case is written to verify that batched updates can be applied when using Zustand with React’s rendering system.
1. Zustand Store Setup: The first step involves creating a Zustand store using the create function:
const useBoundStore = create( (set) => ({ count: 0, inc: () => set((state) => ({ count: state.count 1 })), }))
Here, the store maintains a simple state with a count property initialized to 0 and an inc function to increment the count. The set function is Zustand’s way of updating the state, similar to setState in React.
2. Counter Component: The Counter component uses the useBoundStore to retrieve the current count and the inc function:
const { count, inc } = useBoundStore()
This component subscribes to the store’s state, and any changes to count will cause it to re-render with the new value.
3. Using ReactDOM.unstable_batchedUpdates for Performance: Inside the useEffect hook, the inc function is called twice within a ReactDOM.unstable_batchedUpdates block:
useEffect(() => { ReactDOM.unstable_batchedUpdates(() => { inc() inc() }) }, [inc])
This is where the magic happens. Normally, each call to inc() would trigger a separate update, causing two renders. However, by wrapping these calls in unstable_batchedUpdates, React is able to process them together in a single update, resulting in only one render. This optimizes performance by reducing the number of renders, which is especially useful in performance-critical applications.
4. Rendering the Component and Asserting the Result Finally, the component is rendered, and the test waits for the count to reach 2:
const { findByText } = render(>, ) await findByText('count: 2')
This assertion ensures that after two increments, the count is correctly updated and rendered as "count: 2".
ReactDOM.unstable_batchedUpdates is a method provided by React that allows multiple state updates to be processed in a single render cycle. By default, React batches updates triggered inside event handlers (for example, click event), meaning that if you update multiple states in response to a user interaction, React will render the component only once. However, outside of event handlers (like within setTimeout or useEffect), updates are not batched automatically.
But this has changed after React 18. Below are the screenshots picked from react.dev
Keep in mind, documentation suggests that updates inside of timeouts, promises, native event handlers or any other event will batch the same way as updates inside of React events. But in this Zustand’s test case, batch updates are applied inside useEffect`.This is where unstable_batchedUpdates becomes useful. It forces React to group multiple state updates into a single render, even outside of event-driven contexts, minimizing re-renders and improving performance.
Example:
Without unstable_batchedUpdates:
inc() // triggers one render inc() // triggers another render
With unstable_batchedUpdates:
ReactDOM.unstable_batchedUpdates(() => { inc() // triggers only one render for both updates inc() })
The method is labeled “unstable” because it’s not part of React’s official public API, but it is still widely used in the community for performance optimizations. It may become more stable or integrated as part of React’s new concurrent rendering capabilities in the future.
Fun fact: Zustand’s 4.5.5 release uses the version — 19.0.0-rc.0
Zustand is a lightweight state management library that works with React’s component lifecycle. Although Zustand efficiently handles state updates, React’s reactivity system will trigger renders every time the state changes. In scenarios where multiple state changes occur in a short period, using ReactDOM.unstable_batchedUpdates can prevent multiple re-renders and batch the updates, allowing for a smoother, more efficient user experience.
In the test case provided, calling inc twice within a batched update ensures that the count only updates once, making it more efficient compared to running each update individually.
At Think Throo, we are on a mission to teach the advanced codebase architectural concepts used in open-source projects.
10x your coding skills by practising advanced architectural concepts in Next.js/React, learn the best practices and build production-grade projects.
We are open source — https://github.com/thinkthroo/thinkthroo (Do give us a star!)
Up skill your team with our advanced courses based on codebase architecture. Reach out to us at [email protected] to learn more!
https://github.com/pmndrs/zustand/blob/v4.5.5/tests/basic.test.tsx#L175C7-L175C39
https://dev.to/devmoustafa97/do-you-know-unstablebatchedupdates-in-react-enforce-batching-state-update-5cn2
https://dev.to/jackbuchananconroy/react-18-what-s-changed-automatic-batching-13ec
https://react.dev/blog/2022/03/08/react-18-upgrade-guide#automatic-batching
https://github.com/pmndrs/zustand/blob/v4.5.5/package.json#L246C4-L247C32
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3