React更新嵌套数组单条子项时如何避免无用的全量重渲染?
React嵌套数组更新仅重渲染变更子组件解决方案
问题根因
当前性能问题由两个核心原因共同导致:
- 子组件
TableHead没有做渲染拦截,默认父组件重渲染时所有子组件都会同步重渲染 - 传给子组件的回调函数每次父渲染都会生成新的引用,即使子组件加了浅比较逻辑也会判定为props变化,触发无效重渲染
可行解决方案
1. 用React.memo包裹子组件TableHead
React.memo会对传入组件的props做浅比较,只有props发生变化时才会触发组件重渲染:
// TableHead组件导出时改造 import React from 'react' const TableHead = React.memo((props) => { // 原有组件的所有逻辑保持不变 return ( // 原有JSX结构保持不变 ) }) export default TableHead
你更新uniques数组时仅修改了对应下标的子数组引用,其他下标的uniqueData引用没有变化,浅比较会判定为props未变更,不会触发重渲染。
2. 父组件的回调函数用useCallback包裹稳定引用
你当前直接在JSX里写tableSearch={(e) => tableSearch(e)}这类匿名函数,每次父组件渲染都会生成新的函数引用,导致React.memo的浅比较失效,需要做两处改造:
- 所有传给子组件的回调都用
useCallback包裹,指定正确的依赖项 - JSX里传props直接传函数本身,不要额外包一层匿名函数
父组件代码改造示例:
import React, { useCallback } from 'react' // 父组件内的回调改造 const tableSearch = useCallback((e) => { // 原有tableSearch的逻辑保持不变 }, [/* 填写该函数用到的所有外部依赖项 */]) const handleCheckbox = useCallback((e) => { // 原有handleCheckbox的逻辑保持不变 }, [/* 填写对应依赖项 */]) const ifAnyChecked = useCallback((e) => { // 原有ifAnyChecked的逻辑保持不变 }, [/* 填写对应依赖项 */]) // 渲染部分的props传递改造 {uniques.map((uniqueData, index) => { return ( <th key={index}> <div className="searchContainerWrapper"> <div className="searchBox"> <div id={index} className="options"> <TableHead index={index} keys={props.keys} tableSearch={tableSearch} // 直接传useCallback包裹后的函数,不要包匿名函数 handleCheckbox={handleCheckbox} unique={uniqueData} ifAnyChecked={ifAnyChecked} /> </div> </div> <button> <SearchIcon /> </button> </div> </th> ); })}
3. 可选优化:稳定其他props引用
如果传给TableHead的keys prop是父组件内动态生成的数组/对象,需要用useMemo包裹保证引用稳定,避免不必要的重渲染:
const stableKeys = useMemo(() => props.keys, [props.keys]) // 传props时用stableKeys代替props.keys
效果验证
你可以在TableHead组件内加一行console.log('TableHead渲染,下标:', props.index),触发搜索后只会打印对应修改的containerID的下标,其他下标组件不会触发重渲染。
内容的提问来源于stack exchange,提问作者Shota Donguzashvili
相关产品推荐
相关产品推荐

