Global State Management with Zustand

Have you ever wondered what specific challenges in the React ecosystem led to the creation of Zustand?

In the ever-evolving landscape of React, state management has always been a central challenge. While powerful libraries like Redux offered structure, they often came with the cost of heavy boilerplate. On the other hand, React's built-in Context API, while simple, presented performance pitfalls, re-rendering every component that consumed it on any state change. It was out of these challenges that Zustand was born—a small, fast, and scalable state management solution designed with a "less is more" philosophy.

What Problems Does Zustand Solve?

To appreciate Zustand, we must first understand the problems it was built to fix.

1. Escaping Redux Boilerplate 🤯

For years, Redux was the de-facto standard for global state. But its verbosity was a common complaint. Setting up actions, reducers, dispatchers, and connecting them all required a significant amount of code before you could even manage a single piece of state.

Zustand's solution is radical simplicity. A store is a simple object created with a function. State and the actions that modify it live together.

// The old way with Redux might involve multiple files... // actions.js, reducers.js, store.js

// The Zustand way: import { create } from 'zustand';

const useBearStore = create((set) => ({ 
    bears: 0, 
    increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
    removeAllBears: () => set({ bears: 0 }),
 }));

2. Fixing Context API's Performance Bottleneck 🐌

The React Context API is great for passing state down the component tree without prop-drilling. However, its major flaw is performance. When any value in the context changes, every single component consuming that context re-renders.

Imagine a user profile context with name, email, and theme. If a component only displays the name, it will still re-render when the user changes the theme. This causes unnecessary renders and can slow your app down significantly.

Zustand solves this with selective subscriptions. Components can "select" only the pieces of state they care about. They will only re-render if that specific piece of state changes.

function BearCounter() {
  // This component only cares about the 'bears' count.
  // It will NOT re-render if another part of the store changes.
  const bears = useBearStore((state) => state.bears);
  return <h1>{bears} around here ...</h1>;
}

3. Solving Critical Technical Hurdles

Zustand was also engineered to solve modern React challenges that other solutions struggle with:

  • The Zombie Child Problem: This occurs when a component makes an async request, unmounts before the request completes, and then tries to update its state upon completion, causing a memory leak or error. Zustand’s hooks automatically handle unsubscribing from the store when a component unmounts, elegantly preventing this issue.

  • React Concurrency & Tearing: In React 18+, concurrent rendering can cause a UI "tear," where different components display different versions of the same state in a single render. Zustand is built with this in mind, using the official useSyncExternalStore hook to guarantee that your UI always has a consistent and up-to-date view of your state.

  • Context Loss: React Context is only accessible to components wrapped within its <Provider>. You can't access it from utility functions or other non-React parts of your application. A Zustand store, however, is a vanilla JavaScript module. You can access or update your state from anywhere in your code, completely decoupling your state logic from your UI tree.

Store creation and management with Zustand 👨‍💻

Let's build a simple store.

Step 1: Installation

First, add Zustand to your project.

npm install zustand
# or
yarn add zustand

Step 2: Creating Your Store

Create a file, for example src/store/useAuthStore.js in frontend, and define your store. We'll manage a user's authentication status and name.

// src/store/useAuthStore.js

import { create } from "zustand";

//variable and methods which we will use globally
export const useAuthStore = create((set) => ({
  authUser: null,
  isLoggingIn: false,


  login: async (data) => {

    //updating the state
    set({ isLoggingIn: true });
    try {
     //call your api
    } catch (error) {
      console.log("error loging In");
    } finally {
      set({ isLoggingIn: false });
    }

  },
}));

Here, set is the function you use to update the state.

Step 3: Using the Store in Your Components

Now, you can use the useAuthStore hook in any component to access state and actions.

import React, { useState } from "react";
import { useAuthStore } from "../../store/useAuthStore";

const Login = () => {

  const { login, isLoggingIn } = useAuthStore();

  const onSubmit = async (data) => {
    try {
      await login(data);
    } catch (error) {
      console.error("logging in failed:", error);
    }
  };

  return (
    <div>
      {/*Handling ui*/}
    </div>
  );
};

export default Login;

Beyond the Basics: Middleware & Async Actions

Zustand's power extends further with middleware. You can easily add functionality like:

  • devtools: Connect your store to the Redux DevTools for easy debugging.

  • persist: Persist your store's state to localStorage or sessionStorage.

  • immer: Mutate state directly in a safe, immutable way.

Why zustand over redux?

Why zustand over context?

  • Less boilerplate

  • Renders components only on changes

  • Centralized, action-based state management

State manager integration architecture

State manager integration architecture refers to the patterns and principles used to connect a state management library to a user interface (UI) framework. It defines how application data flows, how state is updated, and how side effects like API calls are handled, ensuring a predictable and maintainable application structure.

For more Details:

zustand Docs : https://github.com/pmndrs/zustand?tab=readme-ov-file

0
Subscribe to my newsletter

Read articles from Syed Wasif Hussain directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Syed Wasif Hussain
Syed Wasif Hussain