第六章 React Hooks
内容前瞻
本章将深入探讨 React Hooks 的核心概念与使用场景,涵盖 useState
、useEffect
、useRef
、useMemo
、useCallback
和 useContext
等常用 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
- 链表机制:通过
mountEffect
和updateEffect
管理副作用链表
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. useMemo
与 useCallback
的区别
useMemo
:缓存计算结果,适用于原始值useCallback
:缓存函数引用,适用于引用值
总结
- Hooks 组件:基于函数作用域实现动态更新,结合了函数组件与类组件的优点
useState
:管理组件状态,支持异步批处理与性能优化useEffect
:控制副作用,支持清理函数与依赖项管理useRef
:获取 DOM 引用,支持 Ref 转发与子组件方法暴露useMemo
与useCallback
:缓存计算结果与函数引用,优化性能useContext
:实现组件通信,支持单向数据流与多层数据传递