codez.guru

On this Page

  • What is Middleware in Zustand?
  • Creating a Logging Middleware
  • Composing Multiple Middleware Layers
  • When and Where to Use Middleware
  • Example: Action Tracking in Production

On this Guide

  • Lesson 09: Organizing State with Slices and Modular Stores
  • Lesson 10: Persisting State to localStorage or sessionStorage
  • Lesson 11: Using Devtools Middleware for Debugging
  • Lesson 12: Using Zustand with Immer for Immutable Updates
  • Lesson 13: Using Zustand with Middleware: Logging, Tracking, and Side Effects
  • Lesson 14: Subscribing to External State Changes
  • Lesson 15: Creating Read-Only or Transient State Stores
  • Lesson 16: Testing Zustand Stores with React Testing Library
  • Lesson 17: Using Zustand in Server-Side Rendering (Next.js)

What is Middleware in Zustand?

Middleware in Zustand lets you enhance or wrap your store behavior by intercepting:

  • Actions (set)
  • State updates
  • Store creation

Zustand includes built-in middleware like devtools, persist, and immer, but you can also write your own.


Creating a Logging Middleware

Here’s how to create a simple logger:

import { StateCreator } from "zustand";

const logger =
  <t>(config: StateCreator<t>): StateCreator<t> =&gt;
  (set, get, api) =&gt;
    config(
      (args) =&gt; {
        console.log("[Zustand] Action:", args);
        set(args);
      },
      get,
      api
    );

Use it like this:

const useStore = create<todostore>()(
  logger((set) =&gt; ({
    todos: [],
    addTodo: (text) =&gt; set((s) =&gt; ({ todos: [...s.todos, { text }] })),
  }))
);

Composing Multiple Middleware Layers

You can compose multiple layers easily:

import { devtools, persist, immer } from "zustand/middleware";

create(
  devtools(
    persist(
      immer(
        logger((set) =&gt; ({
          count: 0,
          inc: () =&gt; set((s) =&gt; ({ count: s.count + 1 })),
        }))
      ),
      { name: "counter" }
    )
  )
);

Order matters: outermost wraps everything.


When and Where to Use Middleware

✅ Use middleware for:

  • Analytics & logging
  • Debugging
  • Custom storage or side effects
  • Code organization (ex: splitting effects vs state)

🚫 Avoid using middleware for:

  • Rendering or UI-related logic
  • Over-complicating small stores

Example: Tracking Actions in Production

You can send store actions to analytics:

const tracking =
  <t>(config: StateCreator<t>): StateCreator<t> =&gt;
  (set, get, api) =&gt;
    config(
      (args) =&gt; {
        if (process.env.NODE_ENV === "production") {
          sendToAnalytics(args); // e.g., LogRocket, Segment, etc.
        }
        set(args);
      },
      get,
      api
    );

Summary

  • Zustand middleware gives you clean extensibility
  • Use it for logging, analytics, debugging, and advanced state behavior
  • You can create and stack your own middleware
  • Middleware logic stays separate from UI

Next: Lesson 14 – Subscribing to External State Changes