钩子分类学 - 网站代码怎么改 03/10
- 2026-09-26 07:00:38
React 有十几个 hooks,看得头大。但实际上必须学的只有四个。
今天就来分个类。
按必要性分类
按照“需要记忆”的等级,分成三类——
1. 必修——生态核心
少了它们,React 功能不完备:
• useState- 少了它,人就没法跟网页交互了• useEffect- 少了它,没法和外界同步• useContext- 少了它,同级组件之间没法传递属性• useRef- 少了它,没法访问 HTML 元素、有时候没办法访问最新状态值
因为没办法替代,所以几乎每个应用都会用到。
2. 选修——改进性能
是为了改进网页性能,是 UX(用户体验)改进。也就是说,没有它也能工作:
• useMemo- 缓存结果• useCallback- 缓存函数• useTransition- 允许不重要的工作推迟、被打断• useDeferredValue- 延迟更新
3. 不修——提升代码质量
让代码更好写,是DX(开发者体验)上的改进。也就是说,No body cares:
• useReducer- 复杂状态管理(可以用useState实现)• useActionState- 表单状态管理(可以用useState实现)• useEffectEvent- 一个东西会变化,但不想因为它引起组件重新渲染(可以用useRef实现)
但实际上,像 useActionState 确实非常好用。一个复杂表单写十来个状态,代码太丑了也不行。后面会专门写一篇。
按渲染行为来分
React 的组件是“纯”(pure)函数:只要参数一样,每次渲染就一样。这是它概念简单之处。但真这样网页就是死的了(静态),可现在的网页又都讲究生动(reactive)。
所以简单概念必须有例外——组件的状态是保存在组件外面的。就像是隐藏的参数,每次变了都会导致组件重新渲染(“画在网页上”)。这个保存的机制就是钩子——钩住一个个外部的稳定变量(简称“外稳变量”;虽然可以简单记成“全局变量”,但细究起来这俩不是一回事)。
最常见的钩子是useState,setStateA 函数就是在修改外稳变量(不妨叫它 stateA)。每次 stateA 改动,都会触发组件重新渲染。
这里要说清楚:是 stateA 导致了组件重新渲染;而不是重新渲染这个动作导致 stateA 变化/重置。其他变量就不一样了,比如let a = 1。不管 a 在组件内发生了什么变化,重新渲染都会导致它被重置成 1。
从这个意义上,所有的钩子都是“跨渲染”不变的。
这里头又有一个很特殊。它很像 useState,可以跨渲染保存状态,也可以主动改变状态值,却不会因为值的变化而导致重新渲染:useRef。——这又是因为它是唯一一个指针型钩子——钩住的是内存中变量的位置,而不是这个位置存储的具体数值。
useRef 特别适合那些需要关注最新的值,但又不需要把值显示在页面上的那些关键/底层状态(比如某个播放器窗口元素,上一个状态值,当前的项目 id 等等)。
和几个常见的钩子的对比如下:
| useState | ||||
| useReducer | ||||
| useContext | ||||
| useRef | ||||
| useEffect | ||||
| useEffectEvent | ||||
| useMemo | ||||
| useCallback | ||||
| useTransition | ||||
| useActionState | ||||
| 普通变量 |
再次注意,
1. 所有钩子都是跨渲染不变的(again,因为它们都是“钩住”了外稳变量) 2. 只有 useRef是“可变的”(此时,它所“钩住”的地址本身没有变化;只是地址里存储的值变了);这个特性可以用来解决“闭包陷阱”——这就是另外一个复杂问题了。下一篇再详细写。