
Part 2 is about performance mastery. Because here’s the truth:
Zustand is only as performant as your selector discipline.
The Hidden Engine: Subscription-Based Rendering
When you write this:
const user = useStore((s) => s.user)
You are not just selecting a state. You are creating a subscription.
Internally, Zustand:
- Stores your selector
- Subscribes to state updates
- Runs equality comparison
- Triggers re-render only if the selected value changed
This is fundamentally different from naïve global state systems.
The Dangerous Pattern
const { user, theme } = useStore()But this subscribes to the entire store.
Meaning: In any state change anywhere causes a re-render, even if only 1 item changed.
Referential Equality — The Silent Killer
Now let’s talk about the real issue: reference identity.
Example:
set({ user: { name: "John" } })Even if the name didn’t change, this creates a new object reference. So:
const user = useStore((s) => s.user)
If user reference changes → re-render. Even if logically identical. That’s not a Zustand problem. That’s how JavaScript works.
Accidental Re-renders
const fullName = useStore((s) => ({
first: s.user.firstName,
last: s.user.lastName,
}))This selector returns a new object on every run.
Meaning: Equality check fails, component always re-renders.
Even if firstName and lastName didn’t change.
The Fix: Shallow Comparison
Zustand provides shallow.
import { shallow } from "zustand/shallow"
const fullName = useStore(
(s) => ({
first: s.user.firstName,
last: s.user.lastName,
}),
shallow
)Now, if the first and last didn’t change, re-render does NOT happen.
Why?
Because shallow compare checks property equality instead of object reference.
This is the first real optimization level.
Custom Equality Functions
You can go even deeper. We can use the equality function to avoid re-renders.
const user = useStore(
(s) => s.user,
(a, b) => a.id === b.id
)
The second parameter here (a, b) => a.id === b.id says if the ID of the user changed, re-render, if not, do not re-render
This is powerful but dangerous if misused. Because you’re overriding React’s identity assumptions.
subscribeWithSelector — True Advanced Mode
Zustand also allows out-of-React subscriptions. subscribeWithSelector helps us to lisen store where it is outside the store.
First, we need to understand subscribe
const useStore = create((set) => ({
count: 0,
name: "Eljan",
increment: () => set((s) => ({ count: s.count + 1 })),
}));
// ❌ It run always at the any changings in store
useStore.subscribe((state) => {
console.log("bir şey değişti");
});Problem: You want to watch count But it even works when the name change.
What differs with subscribeWithSelector?
You can select a special slice and re-render.
import { create } from "zustand";
import { subscribeWithSelector } from "zustand/middleware";
const useStore = create(
subscribeWithSelector((set) => ({
count: 0,
name: "Eljan",
}))
);// It works only count changed
useStore.subscribe(
(state) => state.count, // 👈 what do u looking for
(count) => { // 👈 what do u do when it change
console.log("count changed:", count);
}
);
Performance Scenario: Large Dashboard
Imagine you have 50 components, a shared store and frequent updates.
Bad pattern:
const state = useStore()
Good pattern:
const revenue = useStore((s) => s.analytics.revenue)
Only revenue-dependent components update. This is a surgical rendering.
ADVANCED ZUSTAND "3". Middleware Internals & Writing Custom Middleware
ADVANCED ZUSTAND “2”. Selectors, Equality Functions, and Re-render Controls was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.