本章属于 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 };
规则与陷阱
规则的价值在于让多人维护同一个项目时仍能预测行为。下面这些限制看似细碎,实际都在保护组件的输入、输出和生命周期边界。
- Hook 只能在组件或其他 Hook 的顶层调用。
- 不要在 if、循环或嵌套函数里调用 Hook。
- 自定义 Hook 名必须以 use 开头,让工具能检查 Rules of Hooks。
- 提取 Hook 前先确认多个组件确实共享同一类状态逻辑。
练习
练习应当先小后大:先验证一个概念,再把它接入完整页面。不要在没有理解失败原因时复制更复杂的代码。
- 实现 useLocalStorage 并在输入框中使用。
- 实现 useWindowTitle 显示当前章节名。
- 故意在条件分支中调用 Hook,理解为什么违反规则。