Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Connecting Zustand to Redux DevTools

Hello! Let's dive into the next lesson.

In our previous session, we explored the concept of middleware in Zustand, understanding it as a powerful pattern for extending a store's functionality with cross-cutting concerns like logging or persistence.

Today, we'll put that theory into practice with one of the most valuable middlewares available: devtools. This lesson will guide you through integrating the devtools middleware to connect your Zustand store to the Redux DevTools browser extension. This will unlock powerful debugging capabilities, including action logging and time-travel debugging, giving you a clear view into your application's state changes.


1. Prerequisite: Installing the Redux DevTools Extension

Before we write any code, you need the right tool in your browser. The Zustand devtools middleware communicates with the Redux DevTools browser extension. If you don't have it installed, the middleware won't have anything to connect to.

React Zustand Tutorial - 5 using the redux devtools middleware (typescript)

This short clip from the 'React Zustand Tutorial' by Conny Gu shows you how to find and install the correct extension from the Chrome Web Store.

Watch from the beginning until 00:50 to see the installation process. If you're using a different browser like Firefox, you can find the same extension in its respective add-on store.

Once the extension is installed, you should see its icon in your browser's toolbar.

2. Basic Integration with devtools

With the extension ready, let's connect a store. As we discussed in the last lesson, you apply middleware by wrapping your store's creator function.

First, you need to import devtools from zustand/middleware. Then, you simply pass your store's setup function as the first argument to devtools.

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

// The devtools middleware wraps your store creator function
const useBearStore = create(
  devtools(
    (set) => ({
      bears: 0,
      increase: () => set((state) => ({ bears: state.bears + 1 })),
      removeAll: () => set({ bears: 0 }),
    })
  )
);

Now, let's see what this looks like in a running application.

React Zustand Tutorial - 5 using the redux devtools middleware (typescript)

The same video provides a clear demonstration of wrapping a simple 'bear store' and then interacting with it to see the state changes appear in the Redux DevTools panel.

Watch from 00:50 to 02:53. Pay attention to how the state updates and actions are logged in the DevTools panel when the buttons are clicked.

After this step, you can already inspect state, view action history, and even "time travel" by moving the slider in the DevTools UI to revert to previous states.

3. Configuring the DevTools for Clarity and Control

The basic integration is powerful, but in a real application, you'll want more control. The devtools function accepts an optional second argument: a configuration object.

Naming Actions

You might have noticed in the video that the actions were logged with specific names. If you don't provide a name, they will show up as "anonymous", which is not very helpful for debugging.

To fix this, you provide a name for the action as the third argument to the set function. The second argument is for controlling state replacement (which we'll cover later), so for now, you can pass undefined or false.

devtools - Zustand

The official Zustand documentation explains this common issue and provides a clear example of how to fix it.

Read the section titled 'All action names are labeled as 'anonymous''. Focus on the code examples that show the set function before and after adding the action name.

Here is the corrected code structure from our earlier example:

const useBearStore = create(
  devtools(
    (set) => ({
      bears: 0,
      increase: () => set(
        (state) => ({ bears: state.bears + 1 }), 
        false, // Don't replace the state
        'bears/increase' // Action name
      ),
      removeAll: () => set(
        { bears: 0 },
        false, // Don't replace the state
        'bears/removeAll' // Action name
      ),
    })
  )
);

This practice of naming actions is crucial for maintaining a clean and understandable action history in your DevTools.

Naming Stores for Multi-Store Setups

If your application grows to have multiple Zustand stores, you'll find that by default, they all try to connect to the same DevTools instance, leading to confusion. To solve this, you can provide a unique name in the devtools configuration object.

React Zustand Tutorial - 5 using the redux devtools middleware (typescript)

This part of the video demonstrates the problem of multiple stores and shows how to use the name option to distinguish them in the DevTools interface.

Watch from 05:21 to 07:30. Notice how you can switch between the 'Bear Store' and 'Cat Store' from a dropdown in the DevTools after giving them unique names.

Here's how you would apply it in code:

// storeA.js
const useStoreA = create(devtools((set) => ({...}), { name: 'StoreA' }));

// storeB.js
const useStoreB = create(devtools((set) => ({...}), { name: 'StoreB' }));

Disabling DevTools in Production

You should not expose your application's internal state management in a production environment. The devtools middleware makes this easy to control with the enabled flag. By default, it's enabled in development and disabled in production, but you can override this.

React Zustand Tutorial - 5 using the redux devtools middleware (typescript)

This brief clip demonstrates how to use the enabled flag to turn the DevTools connection on or off.

Watch from 02:53 to 03:44. This shows how you can programmatically control the DevTools integration, which is typically done using environment variables like process.env.NODE_ENV !== 'production'.

Example with an environment variable check:

const useMyStore = create(
  devtools(
    (set) => ({ ... }),
    {
      name: 'MyStore',
      enabled: process.env.NODE_ENV !== 'production',
    }
  )
);

4. Middleware Order Matters

In the previous lesson, we noted that the order of middleware composition is important. When using devtools, it should generally be the outermost middleware, or at least outside of any middleware that might transform the state update itself (like immer). This ensures that devtools can accurately log the action and the resulting state change as you intend them.

React Zustand Tutorial - 5 using the redux devtools middleware (typescript)

The video explains the correct ordering when using devtools alongside the immer middleware, another popular choice in the Zustand ecosystem.

Watch from 03:44 to 05:21. The key takeaway is the documented recommendation: devtools should wrap immer (devtools(immer(...))), not the other way around.

This principle applies to other middleware as well. For example, when we cover persist in the next lesson, the typical order is devtools(persist(...)).


Conclusion

You have now learned how to significantly improve your debugging workflow by integrating Zustand with Redux DevTools. This is a standard practice in professional development and will save you countless hours when troubleshooting state-related issues.

Key Takeaways:

  • The devtools middleware requires the Redux DevTools browser extension to be installed.
  • You integrate it by wrapping your store creator: create(devtools((set) => ...)).
  • For better debugging, name your actions using the third argument of the set function: set(..., false, 'action-name').
  • In multi-store applications, use the { name: 'StoreName' } option to distinguish between stores in the DevTools UI.
  • Use the { enabled: ... } option to disable DevTools in production environments.
  • The order of middleware is important; devtools should typically be one of the outermost wrappers.

Next Lesson Preview:

Now that you can debug your store, the next logical step is to make its state persistent. In the next lesson, we will explore the persist middleware, which allows you to automatically save your store's state to localStorage and rehydrate it when the user revisits your application.

Can't find a good explanation? Sign up and we'll make it for you

Sign up