Back to Blog
By AriesZhou · · 4 min read

React State Management

React

As an application grows, state management can easily become chaotic.

React state management is central to application architecture. Good state management makes code clearer and easier to maintain.

1. React built-in state management

1.1 useState: local state

function Counter() {
  const [count, setCount] = useState(0);
  const [user, setUser] = useState({ name: '张三', age: 25 });

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>增加</button>
      <button onClick={() => setUser({ ...user, age: user.age + 1 })}>长大</button>
    </div>
  );
}

1.2 useReducer: complex state

function todoReducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return [...state, action.payload];
    case 'TOGGLE':
      return state.map(todo =>
        todo.id === action.payload ? { ...todo, done: !todo.done } : todo
      );
    case 'DELETE':
      return state.filter(todo => todo.id !== action.payload);
    default:
      return state;
  }
}

function TodoApp() {
  const [todos, dispatch] = useReducer(todoReducer, []);

  return (
    <div>
      <button onClick={() => dispatch({ type: 'ADD', payload: { id: Date.now(), text: '新任务', done: false }})}>
        添加
      </button>
    </div>
  );
}

1.3 Context: cross-component sharing

const ThemeContext = createContext();
const UserContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');
  const [user, setUser] = useState({ name: '张三', id: 1 });

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <UserContext.Provider value={user}>
        <Layout />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
}

function Layout() {
  const { theme, setTheme } = useContext(ThemeContext);
  const user = useContext(UserContext);

  return (
    <div className={theme}>
      <h1>欢迎, {user.name}</h1>
      <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
        切换主题
      </button>
    </div>
  );
}

2. State management best practices

2.1 Minimize state

// ❌ 避免:冗余状态
function BadExample() {
  const [firstName, setFirstName] = useState('张');
  const [lastName, setLastName] = useState('三');
  const fullName = firstName + lastName; // 这不需要是状态

  return <div>{fullName}</div>;
}

// ✅ 推荐:计算属性
function GoodExample() {
  const [user, setUser] = useState({ firstName: '张', lastName: '三' });
  const fullName = `${user.firstName}${user.lastName}`; // 通过计算得到

  return <div>{fullName}</div>;
}

2.2 Lifting state up

// ❌ 避免:状态分散
function Parent() {
  return (
    <>
      <ChildA />
      <ChildB />
    </>
  );
}

// ✅ 推荐:提升到共同父组件
function Parent() {
  const [shared, setShared] = useState('');

  return (
    <>
      <ChildA value={shared} onChange={setShared} />
      <ChildB value={shared} />
    </>
  );
}

2.3 Immutable data

// ❌ 避免:直接修改状态
function badReducer(state, action) {
  switch (action.type) {
    case 'ADD':
      state.push(action.payload); // 直接修改!
      return state;
  }
}

// ✅ 推荐:创建新数据
function goodReducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return [...state, action.payload]; // 新数组
    case 'UPDATE':
      return state.map(item =>
        item.id === action.payload.id ? { ...item, ...action.payload } : item
      );
  }
}

3. Third-party state management

3.1 Redux

// store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';

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

// counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

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

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

// Component.jsx
import { useSelector, useDispatch } from 'react-redux';
import { increment } from './counterSlice';

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

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={() => dispatch(increment())}>增加</button>
    </div>
  );
}

3.2 Zustand (lightweight)

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>
      <p>计数: {count}</p>
      <button onClick={decrement}>减少</button>
      <button onClick={increment}>增加</button>
    </div>
  );
}

3.3 Solution comparison

SolutionProsConsUse cases
useStateSimple, no dependenciesState is scatteredSmall apps
useReducerCentralized logicLearning curveMedium apps
ContextCross-component sharingEasy to overuseGlobal config
ReduxPowerful toolchainLots of boilerplateLarge apps
ZustandLightweight and simpleSmaller communitySmall to medium apps

4. State management patterns

4.1 Atomic state (Jotai)

import { atom } from 'jotai';
import { useAtom } from 'jotai';

const countAtom = atom(0);
const doubledAtom = atom((get) => get(countAtom) * 2);

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

  return (
    <div>
      <p>计数: {count}</p>
      <p>翻倍: {doubled}</p>
      <button onClick={() => setCount(c => c + 1)}>增加</button>
    </div>
  );
}

4.2 Signals

import { signal, computed } from '@preact/signals-react';

const count = signal(0);
const doubled = computed(() => count.value * 2);

function Counter() {
  return (
    <div>
      <p>计数: {count}</p>
      <p>翻倍: {doubled}</p>
      <button onClick={() => count.value++}>增加</button>
    </div>
  );
}

5. Summary

Suggestions for choosing a state management solution:

  • Small apps: useState + useReducer is enough
  • Medium apps: Context + custom Hook, or Zustand
  • Large apps: Redux Toolkit or other mature solutions

Core principles: minimize state, single source of truth, immutable updates.