intro-frontend-course

State Management with Redux or Zustand


1. Introduction to State Management Libraries

As React applications grow in complexity, managing state across multiple components can become challenging. While React’s built-in state management with useState and useReducer works well for simple scenarios, more complex applications may benefit from using a state management library like Redux or Zustand. These libraries provide powerful tools for managing global state, making your application more scalable and maintainable.

Key Concepts:


2. High-Level Overview of Redux

Redux is a popular state management library known for its strict unidirectional data flow and predictable state management. It is particularly useful in large applications where state needs to be shared across many components.

2.1. Core Concepts of Redux
2.2. Basic Example with Redux

Example:

import { createStore } from 'redux';
import { Provider, useSelector, useDispatch } from 'react-redux';

// Define an action type
const INCREMENT = 'INCREMENT';

// Action creator
const increment = () => ({ type: INCREMENT });

// Reducer function
const counterReducer = (state = { count: 0 }, action) => {
  switch (action.type) {
    case INCREMENT:
      return { ...state, count: state.count + 1 };
    default:
      return state;
  }
};

// Create a Redux store
const store = createStore(counterReducer);

function Counter() {
  const count = useSelector(state => state.count); // Accessing state
  const dispatch = useDispatch(); // Dispatching actions

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

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

In this example:

2.3. Benefits of Using Redux

3. High-Level Overview of Zustand

Zustand is a lightweight state management library that provides an easy-to-use and flexible approach to managing state in React applications. It offers a simpler alternative to Redux, focusing on minimalism and ease of integration.

3.1. Core Concepts of Zustand
3.2. Basic Example with Zustand

Example:

import create from 'zustand';

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

function Counter() {
  const { count, increment } = useStore(); // Accessing state and actions

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

function App() {
  return <Counter />;
}

export default App;

In this example:

3.3. More Advanced Example with Zustand

Let’s extend the previous example to include more advanced features such as selectors, derived state, and middleware.

Example:

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

// Create a Zustand store with devtools and persistence middleware
const useStore = create(
  persist(
    devtools(set => ({
      count: 0,
      users: [],
      increment: () => set(state => ({ count: state.count + 1 })),
      addUser: (user) =>
        set(state => ({ users: [...state.users, user] })),
    })),
    {
      name: 'zustand-store', // Name of the storage (localStorage key)
    }
  )
);

// Component to display and increment count
function Counter() {
  const { count, increment } = useStore(state => ({
    count: state.count,
    increment: state.increment,
  })); // Using selector to get specific parts of the state

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

// Component to add and display users
function UserList() {
  const { users, addUser } = useStore(state => ({
    users: state.users,
    addUser: state.addUser,
  }));

  const [name, setName] = React.useState('');

  const handleAddUser = () => {
    addUser({ name });
    setName('');
  };

  return (
    <div>
      <h3>User List</h3>
      <ul>
        {users.map((user, index) => (
          <li key={index}>{user.name}</li>
        ))}
      </ul>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Enter user name"
      />
      <button onClick={handleAddUser}>Add User</button>
    </div>
  );
}

function App() {
  return (
    <div>
      <Counter />
      <UserList />
    </div>
  );
}

export default App;

In this enhanced example:

3.4. Benefits of Using Zustand

4. Deciding Between Redux and Zustand

When choosing a state management library, consider the following factors:


5. Implementing State Management in the Course Project

Apply what you’ve learned by integrating either Redux or Zustand into your course project. Here’s a general approach you can follow:

5.1. Refactor Your Project for Redux
5.2. Refactor Your Project for Zustand

Optimize Performance: Take advantage of Zustand’s ability to select specific parts of the state to ensure that components only re-render when necessary.


6. Video Resources

To reinforce your understanding of state management with Redux and Zustand, here are some helpful videos:

Redux Crash Course (30:30)
Zustand for State Management in React (12:10)
Redux vs Zustand - When to Use Which? (10:24)

7. External Resources

For further reading and exploration: