Zustand Infinite Loops: How to spot and fix them
Zustand Infinite Loops: How to Spot and Fix Them
When building scalable applications with React and Zustand, infinite rendering loops are a common pitfall. They usually occur when selectors return new object references on every render.
Introduction
Zustand is fantastic because of its simplicity, but that simplicity means we have to be careful about referential equality in our selectors.
The Problem
If your selector looks like this:
const { users, activeUser } = useStore(state => ({
users: state.users,
activeUser: state.activeUser,
}))
You are returning a brand new object { users, activeUser } every time the store updates, even if users and activeUser haven't changed! React sees a new reference and re-renders the component.
The Solutions
1. Separate Selectors
The cleanest way is to use atomic selectors:
const users = useStore(state => state.users)
const activeUser = useStore(state => state.activeUser)
2. Shallow Equality
If you must return an object, use Zustand's useShallow hook imported from zustand/react/shallow.
import { useShallow } from 'zustand/react/shallow'
const { users, activeUser } = useStore(
useShallow(state => ({
users: state.users,
activeUser: state.activeUser,
})),
)
Conclusion
By understanding how React handles object references and how Zustand's subscription model works, you can easily avoid these performance-killing infinite loops.