如何分析React Redux中useSelector函数的性能开销及渲染时间影响?
问题背景
我之前有个组件使用了过度宽泛的selector,示例代码如下:
import { useSelector } from 'react-redux'; const aLotOfData = useSelector(state => { return { ...state.object }; });
这个组件会在state中任意值变化时触发重新渲染。于是我对代码做了修改:
import { useSelector } from 'react-redux'; import equalsES6 from 'fast-deep-equal/es6'; const aLotOfData = useSelector(state => { return processKeys(state.object); // 每次返回新对象 }, equalsES6);
其中processKeys函数会筛选所需的特定键子集并转换值,确保组件仅在目标值变化时重渲染。因为返回的是嵌套对象,所以需要用equalsES6做深比较,我也可以把这个钩子拆分为多个独立的selector。
通过React DevTools验证,修改后已经避免了不必要的重渲染,但我担心深比较或processKeys函数存在性能开销,想了解如何分析组件中useSelector钩子的性能成本,证明一个或多个开销较高的钩子仍比不必要的重渲染更划算。已知该组件渲染耗时100ms(来自React DevTools),我需要获取钩子的计时信息来做对比。
解决方案
1. 给钩子逻辑直接添加计时埋点
在selector函数和比较函数中嵌入计时代码,直接打印单次执行的耗时:
import { useSelector } from 'react-redux'; import equalsES6 from 'fast-deep-equal/es6'; const aLotOfData = useSelector(state => { const start = performance.now(); const result = processKeys(state.object); const end = performance.now(); console.log(`processKeys 执行耗时: ${end - start}ms`); return result; }, (prev, curr) => { const start = performance.now(); const isEqual = equalsES6(prev, curr); const end = performance.now(); console.log(`深比较执行耗时: ${end - start}ms`); return isEqual; });
这种方式简单直接,多次测试取平均值能得到更准确的耗时数据。
2. 利用React DevTools Profiler分析
- 打开React DevTools的Profiler面板,录制组件的完整渲染流程。
- 录制结束后,在火焰图中找到目标组件,展开其钩子调用详情,即可查看
useSelector的执行耗时。 - 对比修改前后的总开销:修改前是“每次state变化都触发100ms渲染”,修改后是“单次钩子处理耗时 + 极少次的100ms必要渲染”。例如,若修改后钩子每次处理耗时2ms,之前每10次无关state变化就触发一次100ms渲染,那么修改后的总开销是
2*10 + 100 = 120ms,而修改前是10*100 = 1000ms,显然修改后的方案更划算。
3. 拆分selector对比性能
将单个复杂selector拆分为多个独立的useSelector调用,分别计时对比:
import { useSelector } from 'react-redux'; const key1Data = useSelector(state => processKey1(state.object.key1)); const key2Data = useSelector(state => processKey2(state.object.key2)); // 其他需要的键处理...
每个小selector的处理和比较(因返回单一值或简单对象,浅比较即可)耗时更低,分别计时后加总,与之前的深比较方案对比,可直观看到哪种方案总开销更小。
4. 计算性能收益平衡点
已知组件渲染耗时100ms,假设钩子单次处理耗时为X ms。每次无关state变化时,修改前会触发100ms渲染,修改后仅触发X ms的钩子处理(不会触发渲染)。只要X < 100,每避免一次重渲染就节省了100 - Xms的开销,显然修改后的方案更划算。
内容的提问来源于stack exchange,提问作者Gaurang Tandon

