codelynx.dev
🇫🇷🇬🇧

Back • 24/10/2024

Redux is Dead. Use Zustand Instead...

Written by Melvyn Malherbe on 24/10/2024


Redux is dead. Sure, it's still widely used, but for new projects, I advise against it, especially with the new way of doing things.

The solution now consists of two powerful libraries:

  1. Tanstack Query for managing server-state
  2. Zustand for managing client-state

Especially since most states are now stored in server components and no longer need to be on the front-end.

Why is Redux Dead?

Redux was the first really popular state management library because, at the time, managing state in React wasn't easy.

Redux was used for applications at the level of Meta ADS with thousands of menus, sub-menus, and API calls from all sides.

The state in Meta is very complex to manage and maintain.

Redux allows adding states, managed in "flux," enabling each part of the application to define its "reducer" to communicate with other parts of the application.

Redux was a revolution for:

  • managing the state of complex applications
  • working in teams without stepping on each other's toes

But now it's used by teams of 3 developers on e-commerce sites, you start to see the problem.

Server Components

The new philosophy of React, which pushes towards Server Components, greatly reduces the need for such a complex state manager.

Most data is no longer stored on the client side. When you see this code:

TSX
export default async function ProductPage() {
  const products = await prisma.product.findMany();

  return (
    <ul>
      {products.map((product) => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

Here, in this Server Component, there is no client. Redux couldn't even exist. There's simply no state; we're just displaying a list of products.

But back in the day, you would have needed a useEffect to fetch the data and store it in the state.

In summary, Server Components change many paradigms and further reduce the need for such a complex state manager.

Server-state

However, sometimes you need to store the Server State, meaning the state of our server.

For that, Tanstack Query has established itself as an indispensable leader.

It manages a "cache" of all your data and allows you to update your Server State whenever you want.

TSX
'use client';

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';

export const ProductList = () => {
  const queryClient = useQueryClient();

  const {
    data: products,
    error,
    isLoading,
  } = useQuery({
    queryKey: ['products'],
    queryFn: async () => {
      // get call
    },
  });
  const mutation = useMutation({
    mutationFn: async (newProduct) => {
      // fetch call
    },
    onSuccess: () => {
      queryClient.invalidateQueries(['products']);
    },
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <ul>
        {products.map((product) => (
          <li key={product.id}>{product.name}</li>
        ))}
      </ul>
      <button onClick={handleAddProduct}>Add Product</button>
    </div>
  );
};

Here, you can easily fetch and mutate data; it's simple, efficient, and made for this purpose.

Tanstack Query allows us to manage all the Server State that depends on asynchronous data to function.

But sometimes, there are client-side things. For example, the current state of a Sidebar.

When we talk about Server-state or Client-state, understand that everything here is stored on the client side. We're talking more about the data it contains. The Server-state contains data from the Server, while the Client-state contains data from the Client.

Client-state

For client State, the leader is Zustand, which allows you to create stores that would replace a useContext placed in App.tsx.

You can easily create a store:

TSX
import { create } from 'zustand';

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

And then, you can easily use your store:

TSX
import { useStore } from './store';

export const Counter = () => {
  const { count, increment } = useStore();

  return (
    <div>
      <p>Current count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

This store is accessible everywhere in your application, even outside of React:

TSX
import { useStore } from './store';

// Possible to use it outside of React
const increment = () => {
  useStore.getState().increment();
};

Zustand, unlike Redux, has a "micro" approach to stores. There are no reducers, no dispatch, and no action.

Instead, you'll create many stores; in an application, you might have:

  • useSidebarStore to manage the sidebar state
  • useEditorStore to manage the editor state
  • etc...

One store = one feature.

Why not use useContext? First, because you'll have more code. But also because Zustand supports selectors that allow you to optimize renders.

When a context changes, all components consuming it are re-rendered, even those not using the modified data.

Whereas with zustand, it's possible to select the data:

TSX
import { useStore } from './store';

export const CounterIncrement = () => {
  const count = useStore((state) => state.increment);

  return (
    <div>
      <button onClick={count}>Increment</button>
    </div>
  );
};

This component will never be re-rendered because the increment method will never change (normally).

When to Use Redux?

Redux is dead in the vast majority of applications. If your application heavily depends on server-side data:

  • use Server Components
  • use Tanstack Query

If your application needs a bit of client-side data:

  • use Zustand

But in the rare case where you're creating an application as complex as Meta ADS, or a ticket manager where a lot of data is interrelated and it's a joyful mess... good luck.

But also here, in this rare case representing 5% of applications, use Redux.

Conclusion

Redux is almost dead... at least for the majority of applications. I've shared my advice; it's up to you to follow it.

You can learn to better use React and Zustand in my BegiNReact course:

Le meilleur moyen d'apprendre React !

Rejoins par développeurs, cette formation reçoit une note de 4.7 / 5 🚀

Reçois 12 leçons premium pour maîtriser React et faire partie des meilleurs

You might also want to learn why you don't need useCallback or the difference between a prop and a state in React.