FORMA

State 与 Reducer

Hooks 让函数组件拥有 state 与副作用能力。本文介绍 useStateuseReducer。见 React 基础

useState

tsx
import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button type="button" onClick={() => setCount((c) => c + 1)}>
      {count}
    </button>
  );
}
要点说明
更新是替换setCount(1) 用新值替换旧 state
函数式更新setCount(c => c + 1) 基于上一状态计算,适合连续更新
批量更新同一事件处理函数内多次 setState,React 18 会批量处理后再渲染(见 自动批处理
初始值惰性计算useState(() => expensiveInit()) 仅首次渲染执行

状态不可变更新

对象与数组应创建新引用,勿直接修改原 state:

tsx
// 对象
setUser((u) => ({ ...u, name: "新名字" }));

// 数组
setItems((items) => [...items, newItem]);
setItems((items) => items.filter((x) => x.id !== id));

useReducer

适合 state 结构复杂或下一状态依赖多种 action 类型:

tsx
type State = { count: number };
type Action = { type: "inc" } | { type: "dec" } | { type: "reset" };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case "inc":
      return { count: state.count + 1 };
    case "dec":
      return { count: state.count - 1 };
    case "reset":
      return { count: 0 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <>
      <span>{state.count}</span>
      <button type="button" onClick={() => dispatch({ type: "inc" })}>
        +1
      </button>
    </>
  );
}

Redux Toolkit 的 reducer 风格与此类似,见 状态管理

Hooks 规则

  1. 只在函数组件顶层自定义 Hook 顶层调用,勿放在条件、循环内。
  2. 只从 React 函数或自定义 Hook 中调用 Hooks。

违反规则会导致 Hook 调用顺序错乱。可用 eslint-plugin-react-hooks 静态检查。

参考文献

以下链接在编写时均可正常访问:

Series

hooks

4 / 4