React性能调试好帮手useWhyDidYouUpdate
大家好,我是前端西瓜哥。
最近在尝试优化 React 组件,使用了 React.memo() 去缓存组件的渲染结果。
但有一个问题,就是要使 React.memo() 的缓存生效,需要保持 props 对象的浅比较结果为 true。
所以我们需要通过 useCallback 或 useMemo 处理一些对象类型的 prop,让它们保持指向原来的内存对象。
在 props 少的时候还好,但一旦多了之后,我们就比较难通过肉眼确认是哪个 prop 导致缓存失效。
怎样才能够方便地知道 props 的哪个属性发生了改变呢?
你可以试试 useWhyDidYouUpate。 useWhyDidYouUpate
useWhyDidYouUpate 是一个第三方 React Hooks,来自优秀的 ahooks 库。
名字很直白:Why did you update,意思就是 "你(组件)为什么更新了?"。
顾名思义,useWhyDidYouUpate 的作用是 帮助开发者排查是哪个属性改变导致了函数组件重渲染 。
用法很简单,传入一个标识符字符串(通常为组件名)、以及要进行对比的对象(通常为 props)。 useWhyDidYouUpdate("Counter", props);
useWhyDidYouUpdate 会保存好上一次传入的 props,然后和新传入的 props 进行比较,找出不同的属性,将它们打印到控制台。
我们来看个示例: import { useWhyDidYouUpdate } from "ahooks"; import { useState } from "react"; function Counter(props) { useWhyDidYouUpdate("Counter", props); return ( {props.title} {props.count} ); } export default function App() { const [count, setCount] = useState(0); return ( ); }
点击 "+ 1" 按钮,然后就会在控制台看到下面输出:
这样我们就可以知道,是因为 count 从原来的 0,变成了现在的 1,导致了 Counter 组件的更新。
在线 demo:
https://codesandbox.io/s/u279ov?file=/src/App.js 实现
useWhyDidYouUpdate 的实现不是很复杂,我们直接贴源码(去掉 TS 类型标注)分析一下。 function useWhyDidYouUpdate(componentName, props) { const prevProps = useRef({}); useEffect(() => { if (prevProps.current) { // 提取新旧 props 的属性,生成数组 const allKeys = Object.keys({ ...prevProps.current, ...props }); const changedProps = {}; allKeys.forEach((key) => { // 对比 新旧 prop[key],如果不同,记录到对象中 if (!Object.is(prevProps.current[key], props[key])) { changedProps[key] = { from: prevProps.current[key], to: props[key], }; } }); if (Object.keys(changedProps).length) { // 输出到控制台 console.log("[why-did-you-update]", componentName, changedProps); } } // 更新 prevProps prevProps.current = props; }); }
首先用 useRef 来声明一个 prevProps 变量,用来保存上一次的 props。
函数组件中,ref 可以实现类组件的实例属性的效果,确保每次渲染时可以保持原来的值。
然后将新旧 props 对象的属性提取出来,生成一个属性数组 allKeys。
遍历这个数组,去对比新旧 prop[key]。如果不同,记录到 changedProps 对象中。
最后输出改变的内容,并更新 prevProps。 结尾
当你尝试通过 React.memo() 给组件添加缓存时,却发现没能按照预期触发缓存,想要看看是哪个 props 发生了变化。
那么,你可以用 useWhyDidYouUpdate 来检查到底是哪些 prop 发生了改变。
当然不仅限于 props,我们也可以用 state 或其他对象上。
我是前端西瓜哥,欢迎关注我,学习更多前端知识。
王者曾经的扛把子英雄,如今连做小弟都不配,是官方毁了他们如今的王者荣耀用户,依旧以老玩家为主,因为目前游戏热度显著降低,新玩家入坑的可能性很低,只有那些已经收藏诸多皮肤的玩家还舍不得离开,即使游戏体验低到了难以接受的地步,也还存在一些幻
山海神迹打好基础赢在起跑线上,2030级剧情详解波澜壮阔的战争永不停息,王朝颠覆的旋律长鸣大地!国战网游山海神迹新服8月12日即将开启,今天小编就为大家带来山海神迹里20级以上的剧情,帮助大家打好基础,赢在起跑线上!每天进入游戏
王者荣耀弱化暗信很强,并非难以克制!选这五位英雄轻松拿捏他文丹青解说原创文章盗载必究S28赛季,打野刀和法球类装备的改动,让李信(以下简称暗信)尝尽了甜头,在边路英雄纷纷放弃使用惩击之时,召唤师技能弱化,潜移默化般的成为了暗信的首选技能。
空调除湿模式真的可以除湿吗空调除湿模式真的可以除湿吗?关于空调的除湿功能是不是能除湿,很多人有疑问。答案是肯定的。是可以除湿的。我们在打开除湿模式的时候,从排水管中排出的水就可以看出,这些水都是从室内空气中
盘点王者荣耀里亚瑟有怎样的背景亚瑟大家都不陌生最开始玩这款游戏的时候都是亚瑟跟咱们一起进行新手训练,可以说是王者荣耀新手玩家必备的英雄之一,在游戏中每一个英雄都会有他自己的背景故事,下面小编就带大家来看看亚瑟的
LOL最冷门英雄重做完成乌迪尔4种形态更新,R技能照搬冰鸟大招在LOL神话版本到来之后,乌迪尔凭借涡轮炼金罐这件装备,在打野位快速火了起来,在职业赛场上一度达到非办必选的地步,但很快就惨遭设计师削弱,这个英雄也一下子被打回原形,在如今的12。
英雄远征终于又开始了玩英雄杀的玩家知道不,最近英雄杀又推出了极限远征这一有难度也蛮有趣的玩法活动了(这活动相当令人心水)。不仅可以拿稀有元神,还可以兑换游戏道具当然相比刚推出时远征福利已经下降了不少,
华硕推出新款一体机前后双屏设计,搭载i711700B一体机作为一种形态比较特殊的产品,用上一些奇特配件或者配置的可能性一直都很高,比如最近华硕推出的ExpertCenterE5一体机,就是一款比较奇特的代表产品。第一个比较特别的配置
家用食材净化机哪个牌子好,食材净化机科普家用食材净化机哪个牌子好?冰尊家用食材净化机名列前茅!家用食材净化机因为可以深度净化农药残留激素和细菌等有害物质,在近几年得到飞速发展。那么家用食材净化机哪个牌子好?下面科普。1冰
大侦探迎战古神!福尔摩斯觉醒重制版发布预告此前开发商Frogwares宣布正在重制2006年发售的冒险游戏福尔摩斯觉醒。本作预计登陆PS5PS4XSXSXboxOneSwitch和PC平台,一起来了解下吧。在福尔摩斯觉醒重
暗影西游黑暗光年直通副本推荐剑舞龙城焰火屠魔副本S级全通攻略嗨,各位朋友们大家好呀,我是你们最亲爱的朋友毓玉今天给大家分享下一些游戏心得哦小小见解欢迎指正!黑暗光年地图众多,其中焰火屠魔地图是一个非常重要的地图,只要你有能力提高副本评价,那