EL

Eljan Simuratli

3/10/2026

ADVANCED ZUSTAND "1". Zustand Mental Model: How it Differs from Redux?

4 Mins Read
ADVANCED ZUSTAND "1". Zustand Mental Model: How it Differs from Redux?

ADVANCED ZUSTAND “1”. Zustand Mental Model: How it Differs from Redux?

What is Global State?

  • The data needed by multiple components
  • Situations where we don’t want to perform prop drilling.
  • Values that must stay synchronized across different parts of the UI

Example: Auth User

function Navbar() { const user = ??? // needs access}function Dashboard() { const user = ??? // also needs access}

If you lift the state too high, you get prop drilling:

<App user={user}> <Layout user={user}> <Navbar user={user} /> <Dashboard user={user} /> </Layout></App>

Redux solves this problem using the Flux architecture.

But the real question is:

Does global state really need reducer + action + dispatch every time?

The Redux Mental Model:

Action -> Reducer -> Store -> Re-render

Example:

dispatch({ type: "SET_USER", payload: user }) //Action

// Reducerfunction reducer(state = initialState, action) { switch (action.type) { case "SET_USER": return { ...state, user: action.payload } default: return state }}

//Componentconst user = useSelector((state) => state.user)

Redux is predictable because it treats state changes like domain events.

This is powerful for:

  • Complex business workflows
  • Audit trails
  • Large enterprise systems
  • Time-travel debugging

But here’s the cost:

  • Boilerplate
  • Indirection
  • Mental overhead

Even a simple UI state becomes ceremonial.

The Breaking Point: UI State vs Business State

Consider this example: You want to open a modal.

Redux version:

//Actiondispatch({ type: "OPEN_MODAL" })//Reducercase "OPEN_MODAL": return { ...state, isModalOpen: true }

Now compare Zustand.

Zustand Mental Model (Subscription-Based State).

Zustand removes the event pipeline.

import { create } from "zustand"const useStore = create((set) => ({ user: null, isModalOpen: false, setUser: (user) => set({ user }), openModal: () => set({ isModalOpen: true }), closeModal: () => set({ isModalOpen: false }),}))

Component:

const isModalOpen = useStore((s) => s.isModalOpen)const openModal = useStore((s) => s.openModal)

Mental model:

  • Components subscribe to specific slices
  • Calling set() updates state
  • Only affected subscribers re-render

The Critical Difference: Subscription Granularity

Redux subscription:

const user = useSelector((state) => state.user)

Zustand subscription:

const user = useStore((s) => s.user)

Superficially similar.

But here’s the important part:

In Zustand, each selector creates an independent subscription.

Example:

const user = useStore((s) => s.user)const theme = useStore((s) => s.theme)

If theme changes:
→ user component does NOT re-render.

If you do this instead:

const state = useStore()

Now you subscribe to everything. That’s where performance problems begin. Understanding this is the first advanced step.

Performance Example: Why Mental Model Matters

Let’s simulate a heavy component:

function ExpensiveComponent() { const user = useStore((s) => s.user) console.log("rendering expensive component") return <div>{user?.name}</div>}

Now imagine another part of the app updates:

set({ theme: "dark" })

If your selector is correct:
→ ExpensiveComponent does NOT re-render.

If you destructured the entire state:

const { user, theme } = useStore()

→ It will re-render unnecessarily.

This is why understanding the subscription model matters.

Architectural Philosophy Shift

Redux philosophy:

State change = domain event

A domain event represents a real-world event that occurred within the application’s business logic. "ORDER_CREATED" , "PAYMENT_COMPLATED"

Zustand philosophy:

State change = mutation through controlled setter

Redux enforces discipline through structure.
Zustand gives you flexibility — and expects you to be disciplined.

This is a big mental shift.

Redux is strict by design. Zustand is minimal by design.

Flux Pattern?

Redux is a direct Flux implementation. But Zustand not

Zustand:

  • Does not impose Unidirectional flow
  • Reducer is not necessary
  • It leaves mutation control up to you.

But:

Not applying Zustand Flux doesn’t mean it’s chaotic.

Actually:

Zustand is a subscription-based state container.

This is a crucial difference in mental models.

When Redux Is Actually Better

Let’s be honest.

Redux is better when:

  • You need strict event logs
  • You require deterministic replay
  • You have highly complex async flows
  • You rely on domain-driven architecture

Example:

Order lifecycle in e-commerce:

ORDER_CREATEDORDER_PAIDORDER_SHIPPEDORDER_REFUNDED

When Zustand Feels Right

  • UI-heavy dashboards
  • SaaS admin panels
  • Chrome extensions
  • Feature flags
  • Modal management
  • Filters & sorting

Most frontend apps are 70% UI state, 30% domain state.

Using Redux for everything can be overkill.

ADVANCED ZUSTAND "2". Selectors, Equality Functions, and Re-render Controls
ADVANCED ZUSTAND "2". Selectors, Equality Functions, and Re-render Controls Part 2 is about performance mastery…simuratli.medium.com