3.5 Hooks 增强函数组件


3.5 Hooks:函数组件的增强工具

本节摘要:Hooks 是给函数组件"开挂"的函数,把状态、副作用、性能缓存统一抽象进来。useState 让函数组件有状态,useEffect 管副作用,useMemo/useCallback 优化渲染。理解这三个再加上"规则",就掌握了 React Hooks 的主力。

本节阅读目标
阅读完本节,你应当能够:

  1. 用 useState 管理函数组件状态并更新。
  2. 用 useEffect 表达副作用与生命周期对应(回顾 2.4)。
  3. 知道 useMemo / useCallback 在什么时候真正有用、什么时候是浪费。

一、为什么需要 Hooks

函数组件原本"无状态"——随着组件变复杂,"有状态、有副作用"的需求却越来越多,于是 React 引入 Hooks:一种能"钩进"函数组件内部、挂上状态与副作用能力的函数。它们统一以 use 开头,把能力平铺在函数体里,替代了类组件的 constructor 与生命周期方法。

二、useState:给函数组件搬来状态

function Counter() { const [count, setCount] = useState(0); const add = () => setCount((c) => c + 1); return <button onClick={add}>当前 {count}</button>; }

解构出的两个值:count 是当前状态,setCount 是更新函数。更新的两种传法:传新值,或传一个把旧值变成新值的函数(如上,求值可靠)。

三、useEffect:副作用 + 生命周期

useEffect 接手"副作用":数据请求、订阅、手动改 DOM。第二个参数是依赖数组,它决定了"什么时候重跑":

useEffect(() => { // 挂载后与 title 变化时执行 document.title = `你有 ${unread} 条未读`; }, [unread]); // 只有 unread 变才重跑
  • 空依赖数组:只在挂载时跑一次,返回清理函数对应卸载。
  • 带依赖:依赖变化才重跑,清晰地呼应 2.4 节的"按依赖来"。
  • 返回的清理函数:对应卸载时释放资源。

四、useMemo / useCallback:性能缓存要克制

useMemo 缓存计算结果,useCallback 缓存函数引用。它们的目的都是"在依赖没变时避免无谓重算/重建"。但有个共识:不是每个计算都值得缓存。计算很轻时加缓存反而是负担;真到计算重、或函数要传给被 memo 的子组件时,才用得上。判断标准看代价,而不是跟风。

const total = useMemo(() => items.reduce((s, x) => s + x.price, 0), [items]);

五、自定 Hook:把重复逻辑收进一个带名字的钩子

前面三条铁律里提到"自定义 Hook 也以 use 开头",这条值得单独展开,因为它是 Hooks 复用的主战场。当你在多个组件里反复写同一段"状态 + 副作用",就该抽成一个自定义 Hook。比稿现场拿它和 5.5 节的复用抽象并列评审,能看出它相比 HOC/混入更轻、来源更直接。

举个拖动显示元素位置的例子,几乎每个带浮层的组件都要写:

function useMousePosition() { const [pos, setPos] = useState({ x: 0, y: 0 }); useEffect(() => { const move = (e) => setPos({ x: e.clientX, y: e.clientY }); window.addEventListener('mousemove', move); return () => window.removeEventListener('mousemove', move); // 卸载前清理订阅 }, []); return pos; }

之后任何组件里一行 const { x, y } = useMousePosition(); 就拿到了位置。你不需要在十处复制监听与清理逻辑,也不用担心哪一处忘了清理订阅。这正是"按需复用、就地清理"在 Hooks 形态下的落地——得益于它能复用"状态+副作用"的组合,而类组件时代的 mixin 很难做到这种轻巧。

六、Hooks 的三条铁律

  • 只在最顶层调用:不要放在条件、循环、嵌套函数里,Hooks 依赖稳定顺序登记。
  • 只从函数组件或自定义 Hook 调用:别在普通 JS 里乱用。
  • 自成前缀:自定义 Hook 也要以 use 开头,便于被识别为 Hook。

七、图:Hooks 能力图谱

图:主力 Hooks 的能力分工

图:主力 Hooks 的能力分工

七·一、什么时候该抽自定义 Hook,抽多大会掉坑

要不要抽,比很多写法问题更常见也更该有判断标准。先给一条够用的经验:同一个"状态+副作用"组合在你的代码里出现第三次,就值得抽。第一次是顺手写,第二次开始犹豫,第三次就该把重复收敛成一个带名字的 Hook。标准的反面是"一个逻辑才写了一次就去抽象",提前抽象会让你套一层不存在的通用性,回头又要改。

抽出来后也要防两件事。一是"把太多东西塞进一个 Hook",一个 Hook 管状态、管请求、管缓存,责任一多就难复用也难理解,跟组件该瘦身的道理一样;二是"为了抽象硬写 use 前缀却互相调用出环"——自定义 Hook 之间可以借用别的 Hook,但别让它变成一团你俩都理不清的网。判断尺度还是那条:抽出来之后,是不是让每一处使用者都更短、更直白了。如果答案是"更绕",那这次抽象就是减分项,宁可先不抽。

八、常见坑

  • 忘记依赖数组导致副作用每次渲染都跑,请求满天飞。
  • 在条件里调用 Hook破坏登记顺序,会时好时坏。
  • 滥用 useMemo:轻计算也包一层,反向增加开销、可读性差。

本节要点回顾

  • 三主力:useState 管状态、useEffect 管副作用、memo/callback 管性能。
  • 依赖数组:决定副作用时机,空数组一次、带依赖按变化。
  • 三条铁律:顶层调用、限于组件、use 前缀。
  • 克制缓存:按计算代价判断,不跟风。

Hooks 让函数组件能管状态、副作用、性能。最后一块拼图是事件与表单——用户输入怎么进到 React 里,受控组件怎么做。下一节收尾本章。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U