Skip to content

概念卡片:React Hook

一句话机制:Hook 是 React 16.8 引入的,让函数组件也能拥有 state 和「生命周期副作用」;它以 use 开头(useState / useEffect / useMemo…),且必须在函数组件顶层按固定顺序调用——React 靠调用顺序把每次渲染的 Hook 状态对应起来。

为什么需要 Hook(class 组件的问题)

class 组件能定义 state、有生命周期,但逻辑难以拆分componentDidMount 里混着请求+监听+清理)、this 指向烦人、状态复用要靠高阶组件/render props 层层嵌套。Hook 让函数组件直接拥有这些能力,代码更简洁。

关键代码示例:class vs Hook

jsx
// class 组件(要管理 this)
class Counter extends PureComponent {
  state = { counter: 0 }
  increment = () => this.setState({ counter: this.state.counter + 1 })
}

// 函数组件 + Hook(简洁,无 this)
import { useState } from 'react'
function Counter() {
  const [count, setCount] = useState(0)   // 返回 [值, 设值函数]
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}

useState 返回值解构:const [count, setCount] = useState(0) 等价于 const counter = useState(0); counter[0] / counter[1]重渲染时 React 保留 state,不会重置为初始值

useEffect 处理副作用:

js
useEffect(() => {
  // 挂载 + 依赖变化时执行(发请求、加监听)
  return () => { /* 清理函数:卸载/下次执行前调用 */ }
}, [依赖数组])   // [] 只执行一次;不传则每次渲染都执行

核心 Hook 速查

Hook作用
useState(x)声明 state,返回 [state, setState]
useEffect(fn, deps)副作用,deps 控制执行时机
useMemo(fn, deps)缓存计算结果
useCallback(fn, deps)缓存函数引用
useRef(x)可变引用(不触发渲染)

不变量(必须成立的约束)

  • Hook 只能在函数组件顶层调用,不能在条件、循环、嵌套函数里调——顺序变了状态就错位。
  • useState 的 setter 不自动合并对象setObj({...obj, b:2}) 要手动展开,不像类组件 setState 会合并。
  • useEffect 依赖数组决定何时执行:[] 只执行一次,漏依赖会拿到旧值(stale closure)。
  • Hook 只能在函数组件或自定义 Hook 里用,不能在类组件或普通函数里用。

踩坑案例

  • 现象:在 if 里条件性调用 useState,组件偶发状态错乱。 原因:Hook 靠调用顺序对应状态,条件调用会打乱顺序。解决:把条件判断移到 Hook 内部或放在 Hook 调用之后。

常见误解

  • 以为 Hook 的 setter 和类组件 setState 一样自动合并对象 → 实际不合并,需手动展开。
  • useEffect 依赖数组漏写依赖 → 闭包捕获旧值,逻辑用错数据。

关联

最近更新