Start now →

ADVANCED ZUSTAND “2”. Selectors, Equality Functions, and Re-render Controls

By Simuratli · Published February 27, 2026 · 3 min read · Source: Level Up Coding
Blockchain
ADVANCED ZUSTAND “2”. Selectors, Equality Functions, and Re-render Controls

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:

  1. Stores your selector
  2. Subscribes to state updates
  3. Runs equality comparison
  4. 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.

This article was originally published on Level Up Coding and is republished here under RSS syndication for informational purposes. All rights and intellectual property remain with the original author. If you are the author and wish to have this article removed, please contact us at [email protected].

NexaPay — Accept Card Payments, Receive Crypto

No KYC · Instant Settlement · Visa, Mastercard, Apple Pay, Google Pay

Get Started →