Skip to content

第六章 React Hooks

内容前瞻

本章将深入探讨 React Hooks 的核心概念与使用场景,涵盖 useStateuseEffectuseRefuseMemouseCallbackuseContext 等常用 Hooks

  • Hooks 的基本原理与使用方式
  • 如何通过 Hooks 实现状态管理、生命周期控制、性能优化与组件通信
  • Hooks 的实际应用场景与注意事项

Hooks 组件

Hooks 组件的本质

  • 函数组件:Hooks 组件本质上是函数组件,基于函数作用域实现动态更新
  • 动态与静态的折中:Hooks 组件结合了函数组件的简洁性与类组件的动态更新能力
  • 更新机制
    • 每次更新时,重新执行函数,创建新的函数作用域与闭包
    • 通过 Hooks 管理状态与副作用,避免直接操作 DOM

useState

1. 基本使用

  • 初始化
    • 不需要变化的初始值,直接传递
    • 需要加工的初始值,通过函数传递
  • 特点
    • 不支持部分状态修改,需通过扩展运算符实现
    • React 18 中,useState 更新为异步批处理,减少渲染次数

示例

jsx
const [num, setNum] = useState(1);

for (let i = 0; i < 10; i++) {
  flushSync(() => {
    setNum(num + 1); // 结果:11
  });
}

2. 性能优化

  • 浅比较useState 通过 Object.is 比较状态值,避免不必要的渲染
  • 返回值:返回数组,index[0] 为状态值,index[1] 为更新函数

useEffect

1. 基本使用

  • 无依赖useEffect(callback),类似于 componentDidMount,每次渲染后执行
  • 空依赖useEffect(callback, []),仅在初次渲染后执行
  • 有依赖useEffect(callback, [param]),初次渲染与依赖更新时执行
  • 清理函数useEffect(() => { return () => {} }),组件卸载时执行

2. 执行顺序

  • 优先执行清理函数:组件更新时,先执行上一次的清理函数,再执行新的 callback
  • 链表机制:通过 mountEffectupdateEffect 管理副作用链表

3. 注意事项

  • 异步处理useEffect 不支持直接使用 async 函数,需手动封装
  • useLayoutEffect:在 DOM 更新前同步执行,避免闪烁问题

useRef

1. 基本功能

  • 获取 DOM 引用:通过 ref 获取真实 DOM 或子组件实例
  • 转发 Ref:使用 React.forwardRef 实现子组件 Ref 转发

示例

jsx
const Child = React.forwardRef((props, ref) => {
  return <div ref={ref}>Child Component</div>;
});

2. useImperativeHandle

  • 暴露子组件方法:通过 useImperativeHandle 将子组件的状态与方法暴露给父组件

示例

jsx
useImperativeHandle(ref, () => ({
  stateA,
  methodA,
}));

useMemo 与 useCallback

1. useMemo

  • 缓存计算结果:适用于消耗性能的计算操作,减少不必要的重复计算
  • 使用场景:字符串、数字等原始值的缓存

示例

jsx
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

2. useCallback

  • 缓存函数引用:适用于父子组件通信,避免子组件不必要的更新
  • 使用场景:函数、对象等引用值的缓存

示例

jsx
const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

useContext

1. 组件通信

  • 单向数据流:父组件通过 props 向子组件传递数据,子组件通过回调函数更新父组件状态
  • 多层通信:使用 useContext 实现祖先与后代组件的数据传递

2. 使用方式

  • 创建上下文
    jsx
    const MyContext = React.createContext();
  • 提供数据
    jsx
    <MyContext.Provider value={/* 数据 */}>
      <ChildComponent />
    </MyContext.Provider>
  • 消费数据
    jsx
    const value = useContext(MyContext);

重难点 & 容易忽视的点

1. useEffect 的依赖项

  • 空依赖:仅在组件挂载与卸载时执行
  • 动态依赖:依赖项变化时触发 callback

2. useRef 的性能优势

  • 引用不变useRef 在组件更新前后引用相同,性能优于 createRef

3. useMemouseCallback 的区别

  • useMemo:缓存计算结果,适用于原始值
  • useCallback:缓存函数引用,适用于引用值

总结

  • Hooks 组件:基于函数作用域实现动态更新,结合了函数组件与类组件的优点
  • useState:管理组件状态,支持异步批处理与性能优化
  • useEffect:控制副作用,支持清理函数与依赖项管理
  • useRef:获取 DOM 引用,支持 Ref 转发与子组件方法暴露
  • useMemouseCallback:缓存计算结果与函数引用,优化性能
  • useContext:实现组件通信,支持单向数据流与多层数据传递