跳到主要内容

状态 Hooks 的初始化与契约

如何避免每次渲染都计算初始状态?​

  • 惰性初始化: 给 useState 传初始化函数,让 React 在建立状态时调用;传 createInitial() 则 JavaScript 在每次执行组件时先调用它;
  • 初值变化: 后续传入不同 initialState 不会覆盖已存在的状态,重置方式见保留与重置 state;
  • 纯度检查: 初始化函数不接收参数,应为纯函数,StrictMode 开发检查可能调用两次并忽略一次结果;
写法初始化时普通重新渲染时
useState(createInitial())计算并采用仍计算,但 React 忽略结果
useState(createInitial)React 调用并采用不因传参再次调用
useReducer(reducer, arg, init)使用 init(arg)保留当前状态
function initializeTasks(initialTasks) {
return initialTasks.map((task) => ({ ...task, selected: false }));
}

function Tasks({ initialTasks }) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks, initializeTasks);
return <TaskList tasks={tasks} dispatch={dispatch} />;
}

如何把函数本身存进 state?​

  • 函数歧义: useState 的函数参数被当成 initializer,setter 的函数参数被当成 updater,不能直接用它们保存函数值;
  • 包一层返回: 使用 useState(() => fn) 初始化,以 setFn(() => nextFn) 更新,外层函数返回真正要保存的函数;
const [handler, setHandler] = useState(() => initialHandler);
function replaceHandler() {
setHandler(() => nextHandler);
}