提取可复用的状态逻辑

第九章:自定义 Hook

提取自定义 Hook,复用状态逻辑并遵守 Rules of Hooks。

本章属于 React 教程的核心路线。建议先通读概念模型,再手写最小示例,最后用练习验证自己能否独立复现。

本章目标

本章学习自定义 Hook、复用逻辑、useLocalStorage、useWindowTitle,以及必须遵守的 Rules of Hooks。

阅读本章时,请把每个 API 放回“数据如何变成界面、用户操作如何改变数据”的主线中理解。React 的学习重点不是背诵语法,而是建立可预测的渲染模型。

概念模型

自定义 Hook 是以 use 开头的函数,它可以调用其他 Hook,把状态逻辑从组件中提取出来。它复用的是行为,不是 UI。

你可以把 React 程序看成一棵由组件组成的元素树。每次输入数据、状态或外部系统发生变化,React 会重新计算需要展示的 React element,再用高效的方式更新浏览器中的 DOM。

最小示例

useLocalStorage 同步 state 和 localStorage;useWindowTitle 把页面标题同步到浏览器窗口。

import { useEffect, useState } from "react";

export function useLocalStorage(key: string, initialValue: string) {
  const [value, setValue] = useState(() => localStorage.getItem(key) ?? initialValue);

  useEffect(() => {
    localStorage.setItem(key, value);
  }, [key, value]);

  return [value, setValue] as const;
}

export function useWindowTitle(title: string) {
  useEffect(() => {
    document.title = title;
  }, [title]);
}
type LessonNote = { title: string; done: boolean };\nconst note: LessonNote = { title: 'React 教程', done: false };

规则与陷阱

规则的价值在于让多人维护同一个项目时仍能预测行为。下面这些限制看似细碎,实际都在保护组件的输入、输出和生命周期边界。

练习

练习应当先小后大:先验证一个概念,再把它接入完整页面。不要在没有理解失败原因时复制更复杂的代码。

  1. 实现 useLocalStorage 并在输入框中使用。
  2. 实现 useWindowTitle 显示当前章节名。
  3. 故意在条件分支中调用 Hook,理解为什么违反规则。