Written by: ekwoster.dev on Tue Aug 12

Mastering State Management in React with Zustand: A Lightweight Alternative to Redux

Mastering State Management in React with Zustand: A Lightweight Alternative to Redux

Cover image for Mastering State Management in React with Zustand: A Lightweight Alternative to Redux

Mastering State Management in React with Zustand: A Lightweight Alternative to Redux

When developing React applications, state management becomes a critical concern, especially as your app grows in complexity. While Redux has long been the go-to solution, many developers have found it to be too complex and verbose for certain projects. Enter Zustand β€” a small, fast, and scalable state-management tool for React applications.

In this blog post, we'll dive deep into Zustand, exploring what makes it stand out, how to set it up, and how it compares with other tools like Redux and Context API. Whether you're building a small-scale dashboard or a large single-page application, Zustand may just become your go-to state manager.

🐻 What Is Zustand?

Zustand (which means "state" in German) is a simple and efficient state management solution developed by the creators of Jotai and React Spring. It's a minimalistic library that requires no boilerplate and works seamlessly within the React ecosystem.

πŸ”‘ Key Features

  • No boilerplate: Zustand has a minimal API.
  • No Provider wrapper: Just import your store and use it anywhere.
  • Built on hooks: Uses modern React hooks under the hood.
  • Good performance: Only components reading the state re-render.
  • Support for asynchronous logic: Easily handle async operations like API calls.

βš™οΈ Installing Zustand

Installing Zustand is as easy as running a single command:

npm install zustand

Or with yarn:

yarn add zustand

πŸ“¦ Creating Your First Store

Zustand uses a very simple API to create state stores.

// store.js
import { create } from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
  decrease: () => set((state) => ({ count: state.count - 1 }))
}));

export default useStore;

Then in your React component:

import React from 'react';
import useStore from './store';

export default function Counter() {
  const count = useStore(state => state.count);
  const increase = useStore(state => state.increase);
  const decrease = useStore(state => state.decrease);

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increase}>+</button>
      <button onClick={decrease}>-</button>
    </div>
  );
}

🧠 How Does It Work?

Zustand maintains your state in a centralized store and allows components to subscribe to parts of it selectively. When the selected state changes, only those components re-render.

This makes Zustand more efficient than alternatives like the Context API, which may trigger re-renders on all consumers whenever the context value changes, unless you implement memoization manually.

πŸ” Zustand vs Redux

FeatureZustandRedux
BoilerplateMinimalHigh
Learning CurveEasyModerate/Hard
Middleware SupportCustomizableGood (Redux Toolkit)
DevTools SupportPartialFull
Async SupportNative via setRedux Thunk/Saga required

Zustand isn’t meant to replace Redux for highly complex apps with advanced debugging and time-traveling state. But it’s perfect for apps that simply need shared state with a lighter touch.

πŸ”„ Handling Async Logic

Handling asynchronous operations in Zustand is straightforward. Here's an example of fetching data from an API:

// store.js
import { create } from 'zustand';

const useUserStore = create((set) => ({
  user: null,
  isLoading: false,
  fetchUser: async () => {
    set({ isLoading: true });
    const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
    const data = await res.json();
    set({ user: data, isLoading: false });
  }
}));

export default useUserStore;

In the component:

import React, { useEffect } from 'react';
import useUserStore from './store';

function UserDetails() {
  const { user, isLoading, fetchUser } = useUserStore();

  useEffect(() => {
    fetchUser();
  }, []);

  if (isLoading) return <p>Loading...</p>;

  return user ? <p>{user.name}</p> : <p>No User</p>;
}

πŸ§ͺ Testing Zustand Stores

Some developers are concerned about testability with hook-based state managers. Zustand makes testing easier by exporting the store state, which can be reset or mocked as necessary in tests.

import useUserStore from './store';

// Set initial test state
useUserStore.setState({ user: { name: 'Test User' }, isLoading: false });

You can now run your component/unit tests with a predictable global state.

βœ… When to Use Zustand

Zustand shines in scenarios where:

  • You want to reduce boilerplate
  • Need simple and effective state sharing
  • You are building small to medium SPA applications
  • You prefer hooks-first API
  • You find Redux and Context too heavyweight

πŸ”Œ Zustand Extensions & Middleware

Zustand supports middleware for features like persistence and immutability:

npm install zustand/middleware

Example: Persist Middleware

import { create } from 'zustand';
import { persist } from 'zustand/middleware';

const usePersistedStore = create(persist((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
}), {
  name: 'counter-storage', // name of the item in storage
}));

This store now persists state in localStorage automatically.

🌍 Real-World Use Cases

  • Authentication state: Keep track of logged-in users
  • Theme toggles: Easily manage dark/light modes
  • Global modals: Open/close modals from anywhere
  • Shopping carts: Maintain global cart state

πŸ’¬ Final Thoughts

Zustand makes global state in React a breeze. With its tiny footprint and minimal API, it offers a refreshing alternative to Redux, especially when favoring simplicity and performance. Whether you're building a simple blog site, a dashboard, or a mobile-first app with React Native, Zustand can help manage state efficiently without adding much complexity.

It's not a silver bullet, but for many use cases, Zustand is more than enough β€” and dare we say β€” a joy to use.

πŸ“š Additional Resources

Happy coding! πŸ§ βš›οΈ

βœ… If you need help building performant frontend applications with state management like Zustand, we offer such services.