Back to Blog

State Management in React

Anonymous
March 25, 2024
9 min read

State Management in React: From Context to Redux

Choosing the right state management solution is crucial for building scalable React applications. Let's explore different approaches.

React Context API

Basic Context Setup

import { createContext, useContext, useState } from "react";

const ThemeContext = createContext<{
  theme: string;
  toggleTheme: () => void;
}>({
  theme: "light",
  toggleTheme: () => {},
});

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  const toggleTheme = () => {
    setTheme((prev) => (prev === "light" ? "dark" : "light"));
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export const useTheme = () => useContext(ThemeContext);

Redux Toolkit

Store Setup

import { configureStore, createSlice } from "@reduxjs/toolkit";

const counterSlice = createSlice({
  name: "counter",
  initialState: { value: 0 },
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
});

export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  },
});

export const { increment, decrement } = counterSlice.actions;

Using Redux in Components

import { useSelector, useDispatch } from "react-redux";
import { increment, decrement } from "./store";

function Counter() {
  const count = useSelector((state) => state.counter.value);
  const dispatch = useDispatch();

  return (
    <div>
      <button onClick={() => dispatch(decrement())}>-</button>
      <span>{count}</span>
      <button onClick={() => dispatch(increment())}>+</button>
    </div>
  );
}

Zustand

Simple State Management

import create from "zustand";

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

function Counter() {
  const { count, increment, decrement } = useStore();

  return (
    <div>
      <button onClick={decrement}>-</button>
      <span>{count}</span>
      <button onClick={increment}>+</button>
    </div>
  );
}

Jotai

Atomic State Management

import { atom, useAtom } from "jotai";

const countAtom = atom(0);

function Counter() {
  const [count, setCount] = useAtom(countAtom);

  return (
    <div>
      <button onClick={() => setCount((c) => c - 1)}>-</button>
      <span>{count}</span>
      <button onClick={() => setCount((c) => c + 1)}>+</button>
    </div>
  );
}

Choosing the Right Solution

When to Use Each

  1. Context API

    • Simple state sharing
    • Theme management
    • User preferences
    • Small to medium applications
  2. Redux

    • Complex state management
    • Large applications
    • Need for middleware
    • Time-travel debugging
  3. Zustand

    • Simple global state
    • Minimal boilerplate
    • Small to medium applications
    • Quick setup
  4. Jotai

    • Atomic state management
    • Fine-grained updates
    • React-like API
    • Performance optimization

Conclusion

Key considerations for state management:

  • Application size and complexity
  • Team expertise
  • Performance requirements
  • Development speed
  • Maintenance needs