关于函数内用useEffect实现的usePrevious自定义Hook的疑问
关于usePrevious钩子中useEffect存值与直接赋值的区别
在FlyerChat项目中看到如下usePrevious自定义钩子代码:
import * as React from 'react' export const usePrevious = <T>(value: T) => { const ref = React.useRef<T>() React.useEffect(() => { ref.current = value }, [value]) return ref.current }
调用方式为:
const previousChatMessages = usePrevious(chatMessages);
疑问:在函数中通过useEffect将值存入ref,与直接写ref.current = value之间有什么区别?
核心区别在于执行时机与React渲染周期的配合
直接赋值
ref.current = value:这行代码会在组件每次渲染时同步执行。当组件因为chatMessages变化触发重新渲染时,ref.current会立刻被更新成新的chatMessages值,此时usePrevious返回的其实和当前的chatMessages是同一个值,根本拿不到上一轮的旧值。用
useEffect赋值:useEffect的回调函数会在组件渲染完成(DOM更新后)才执行。组件渲染时,usePrevious先返回ref里保存的旧值,等渲染结束后,再把新的value存入ref。这样下一次组件渲染时,就能通过这个钩子拿到上一轮渲染的旧值,完美实现“获取前一次状态”的需求。
举个具体流程例子:
- 第一次渲染:
ref.current初始为undefined,usePrevious返回undefined,渲染完成后useEffect把当前chatMessages存入ref。 chatMessages更新触发第二次渲染:usePrevious先返回上一次存入的旧chatMessages,渲染完成后useEffect再把新的chatMessages存入ref。- 后续每次渲染重复这个逻辑,保证每次拿到的都是上一轮的旧值。
如果不用useEffect直接赋值,第二次渲染时ref.current会被立刻更新成新值,返回的就不是旧值了,完全达不到这个钩子的设计目的。
内容的提问来源于stack exchange,提问作者Ramin Zandvakili
相关产品推荐
相关产品推荐

