React列表选中项全量重渲染,求移动端性能优化方案
优化方案:阻止OrderRule列表全量重渲染
针对你遇到的选中项时列表全量重渲染的问题,以下是具体优化步骤:
1. 用React.memo缓存列表项组件
React.memo会对组件props做浅比较,只有当props真正变化时才触发重渲染。大部分OrderRule项的props在选中状态切换时不会改变,只有选中项的selected属性会变化,这个缓存能直接生效。
修改OrderRule组件:
import { memo } from 'react'; const OrderRule = memo((props) => { const rule = props.data; // 直接通过props判断选中状态,移除内部维护的state const isSelected = props.selected === rule?.Oid; return ( <div onClick={() => props.setSelectedRule(rule?.Oid)} className={isSelected ? 'your-selected-class' : ''} > {/* ...otherStuff */} </div> ); }); export default OrderRule;
2. 用useCallback固定回调函数引用
父组件中的setSelectedRule每次渲染都会生成新函数,导致子组件props变化触发重渲染。用useCallback固定函数引用,避免不必要的props更新:
修改RulePage代码:
import { useState, useCallback } from 'react'; const RulePage = () => { const [rules, setRules] = useState([]); const [selected, setSelected] = useState(null); // useCallback包裹,依赖项留空(setSelected是React稳定的state setter,无需加入依赖) const setSelectedRule = useCallback((oid) => { setSelected(oid); }, []); return ( rules && <OrderRuleList selected={selected} setSelectedRule={setSelectedRule} rules={rules} {...aLotOfProps} /> ); };
同时简化OrderRuleList,直接传递父组件的回调,避免额外包装函数引发props变化,并且给列表组件也加上React.memo:
import { memo } from 'react'; const OrderRuleList = memo((props) => { return ( props.rules.map((rule) => ( <OrderRule key={rule.Oid} // 必须用唯一且稳定的标识当key,比如rule的Oid,不能用index selected={props.selected} data={rule} setSelectedRule={props.setSelectedRule} {...moreProps} /> )) ); }); export default OrderRuleList;
3. 移除列表项内部的selected状态
你之前在OrderRule里用useState维护选中状态,会导致内部状态和外部props不同步,而且完全没必要——直接通过props.selected和当前项的Oid对比就能判断选中状态,既保证状态统一,也避免了内部state带来的额外渲染。
4. 确保循环渲染的key唯一稳定
map渲染列表项时,必须用每个rule的唯一标识(比如Oid)作为key,不能用数组index。index会在列表项顺序变化时失效,导致React无法正确复用组件,反而可能引发更多不必要的重渲染。
为什么之前的useMemo没生效?
大概率是你没正确处理依赖项,或者把useMemo用在了错误的位置(比如包裹整个列表JSX,但回调函数仍每次更新,导致useMemo依赖变化、缓存失效)。上面的方案从根源上解决了props频繁变化的问题,比单纯用useMemo更有效。
内容的提问来源于stack exchange,提问作者Takkie253
相关产品推荐
相关产品推荐

