React Hooks中如何访问数据类型为对象或数组的prevProps
你遇到的引用类型不生效问题,本质是因为JavaScript中全等比较===对数组、对象等引用类型只会对比内存地址,不会判断内部值是否相等,你在类组件中使用了_.isEqual深比较,在Hooks中只要沿用这个逻辑即可,有两种常用实现方案:
方案1:结合已有usePrevious钩子使用
不需要修改现有的usePrevious,只需要在对比时使用深比较即可,完全对齐类组件的写法:
import { useRef, useEffect } from 'react'; import _ from 'lodash'; // 你原有usePrevious无需修改 const usePrevious = value => { const ref = useRef(); useEffect(() => { ref.current = value; }); return ref.current; }; // 组件内使用 const YourComponent = ({ myArray }) => { // 获取上一次渲染的myArray值 const prevMyArray = usePrevious(myArray); useEffect(() => { // 跳过首次渲染,和componentDidUpdate行为保持一致(componentDidUpdate首次渲染不触发) if (prevMyArray === undefined) return; // 沿用类组件中的深比较逻辑 if (!_.isEqual(myArray, prevMyArray)) { // 你原有componentDidUpdate中的业务逻辑 // do something... } }, [myArray, prevMyArray]); // 组件其余逻辑 return <></>; };
方案2:封装自定义深比较更新钩子
如果需要频繁处理引用类型的更新监听,可以封装专用钩子,简化组件内的写法:
import { useEffect, useRef } from 'react'; import _ from 'lodash'; // 自定义钩子:行为和useEffect一致,但依赖项会做深比较,且首次渲染不触发 const useDeepCompareUpdateEffect = (callback, dependencies) => { // 存储上一次的依赖项 const prevDepsRef = useRef(); // 标记是否为首次渲染 const isFirstRenderRef = useRef(true); // 深比较依赖项是否变化,变化则更新存储值 if (!_.isEqual(dependencies, prevDepsRef.current)) { prevDepsRef.current = dependencies; } useEffect(() => { // 跳过首次渲染 if (isFirstRenderRef.current) { isFirstRenderRef.current = false; return; } // 执行业务回调 callback(); }, [prevDepsRef.current]); }; // 组件内使用 const YourComponent = ({ myArray }) => { // 直接传入需要监听的数组作为依赖,值变化时自动触发回调 useDeepCompareUpdateEffect(() => { // 你原有componentDidUpdate中的业务逻辑 // do something... }, [myArray]); // 组件其余逻辑 return <></>; };
注意事项
- 深比较存在一定性能开销,如果你的数组/对象结构复杂、更新频率很高,建议优先使用Immutable数据结构,保证值变化时引用同步变化,这样可以直接使用原生
useEffect,无需额外深比较。 - 如果你不想引入lodash,可以自行实现适配业务场景的轻量深比较函数替换
_.isEqual即可。
内容的提问来源于stack exchange,提问作者Shuwei
相关产品推荐
相关产品推荐

