1. YouTube Summaries
  2. Zustand: Simplifying React State Management

Zustand: Simplifying React State Management

By scribe 6 minute read

Create articles from any YouTube video or use our API to get YouTube transcriptions

Start for free
or, create a free article to see how easy it is.

Introduction to Zustand

Zustand has quickly become a favorite state management library in the React community. Its simplicity and ease of use make it an attractive option for developers looking to manage application state effectively. In this article, we'll explore what makes Zustand stand out and how it compares to other state management solutions.

What is Zustand?

Zustand is a small, fast, and scalable state management library for React applications. It provides a straightforward API to create and manage global state without the complexity often associated with other state management solutions.

Here's a simple example of how to set up a store with Zustand:

import create from 'zustand'

const useCountStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 }))
}))

In this example, we create a store with a count value and an increment function to update it. The set function provided by Zustand allows us to update the state easily.

Zustand vs Redux Toolkit

Compared to Redux Toolkit, Zustand offers a more streamlined approach to state management. With Redux Toolkit, you would need to:

  1. Set up a new slice
  2. Add the slice to the root reducer
  3. Set up the store creation and provider

Zustand simplifies this process significantly. Once you've created your store, you can access its values and actions using the generated hook:

const count = useCountStore((state) => state.count)
const increment = useCountStore((state) => state.increment)

Size Comparison

One of Zustand's advantages is its small size. The npm package is only 3.1 KB minified, which is:

  • 44 times smaller than the base React package
  • 13 times smaller than Redux (40 KB minified)

This small footprint makes Zustand an excellent choice for projects where bundle size is a concern.

Refactoring to Zustand

To understand the benefits of Zustand in a real-world scenario, let's look at the process of refactoring an existing application to use Zustand.

The Teemo App

Teemo is a sample application with three main screens:

  1. Login and sign-up
  2. Viewing and changing time entries
  3. A timer for creating new time entries

Initially, Teemo used React Context for state management. The refactoring process to Zustand took about an hour and was relatively straightforward.

Refactoring Process

In many cases, Zustand acted as a drop-in replacement for the existing context-based hooks. For example:

// Before (using React Context)
const user = useUser()

// After (using Zustand)
const user = useUserStore((state) => state.user)

The most challenging part of the refactoring process was updating components in the common package that were shared between different versions of the app. Some components that depended on React Context had to be refactored to be pure, affecting all versions of the app.

Handling Side Effects in Zustand

One challenge encountered during the refactoring process was handling side effects, particularly for operations that needed to run when the app started. In this case, the app needed to make an API request to verify if the user was already logged in.

The solution was to interact with the Zustand store outside of React:

const useUserStore = create((set) => ({
  user: null,
  fetchUser: async () => {
    try {
      const user = await getUser()
      set({ user })
    } catch (error) {
      set({ error })
    }
  }
}))

// Run the fetchUser action immediately after creating the store
useUserStore.getState().fetchUser()

This approach has the added benefit of only making the API request once during development, unlike using a useEffect hook which would trigger twice in React's strict mode.

Benefits of Zustand over React Context

One of the main advantages of Zustand over React Context is its ability to prevent unnecessary re-renders. With React Context, any change to the context value causes all subscribed components to re-render. This can lead to performance issues, especially in larger applications.

Zustand solves this problem by:

  1. Not requiring a provider component that wraps the entire app
  2. Sending updates directly to the generated hooks
  3. Allowing components to subscribe to specific state values

This means that components only re-render when the specific state values they're subscribed to change, leading to better performance.

Zustand and Async Operations

Zustand handles async operations elegantly. You can simply call set with the result of an async operation:

const useUserStore = create((set) => ({
  user: null,
  fetchUser: async () => {
    try {
      const user = await getUser()
      set({ user })
    } catch (error) {
      set({ error })
    }
  }
}))

This approach is straightforward and doesn't require any additional middleware or complex promise chains.

Advanced Usage: Selectors and Memoization

Zustand provides powerful features for optimizing performance and preventing unnecessary re-renders. One such feature is the ability to use selectors to subscribe to specific parts of the state.

For example:

const count = useCountStore((state) => state.count)
const increment = useCountStore((state) => state.increment)

By using selectors, components will only re-render when the selected state values change. This is particularly useful for large stores with many values.

You can also use memoization to further optimize performance:

import { shallow } from 'zustand/shallow'

const { count, increment } = useCountStore(
  (state) => ({ count: state.count, increment: state.increment }),
  shallow
)

The shallow comparison ensures that the component only re-renders if the selected values have actually changed.

Zustand in Large-Scale Applications

While Zustand shines in its simplicity for small to medium-sized applications, it's also capable of handling state management in larger, more complex projects. Here are some strategies for using Zustand effectively in large-scale applications:

1. Multiple Stores

Instead of creating one large store, you can create multiple smaller stores for different features or domains of your application. This helps in maintaining a clear separation of concerns:

const useUserStore = create(/* user-related state */)
const useProductStore = create(/* product-related state */)
const useCartStore = create(/* shopping cart state */)

2. Computed Values

You can create computed values directly in your selectors, which will only update when their dependencies change:

const totalPrice = useCartStore(
  (state) => state.items.reduce((sum, item) => sum + item.price, 0)
)

3. Middleware

Zustand supports middleware, allowing you to add custom functionality to your stores. For example, you could add logging or persistence:

import { persist } from 'zustand/middleware'

const useStore = create(
  persist(
    (set, get) => ({
      // your state and actions
    }),
    { name: 'user-storage' }
  )
)

Zustand and TypeScript

Zustand works well with TypeScript, providing type safety for your stores. Here's an example of how to define a typed store:

interface CountState {
  count: number
  increment: () => void
}

const useCountStore = create<CountState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 }))
}))

This ensures that you get proper type checking and autocompletion when using your store.

Conclusion

Zustand has gained popularity in the React community for good reasons. Its lightweight nature, ease of use, and powerful features make it an excellent choice for state management in React applications of all sizes.

Key benefits of Zustand include:

  1. Simplicity: Easy to set up and use with a minimal API
  2. Performance: Efficient updates and prevention of unnecessary re-renders
  3. Flexibility: Works well with both small and large-scale applications
  4. TypeScript support: Provides type safety for your global state

While it may not be the perfect solution for every use case, Zustand offers a refreshing approach to state management that many developers find intuitive and effective. As you build your next React application, consider giving Zustand a try – you might find it simplifies your state management needs significantly.

Remember, the best state management solution is the one that fits your project's needs and your team's preferences. Zustand's growing popularity suggests that for many developers, it strikes the right balance between simplicity and power.

Article created from: https://www.youtube.com/watch?v=14B85quRQhw

Ready to automate your
LinkedIn, Twitter and blog posts with AI?

Start for free