React.memo封装的表格行在头部增删数据时触发全量重渲染问题求解
问题根源与修复方案
1. 列表渲染的key属性位置错误
你当前把key={row.id}写在了RowMemo组件内部的tr标签上,不符合React列表渲染的核心规则:key必须加在map方法返回的直接子元素上,也就是你写的<RowMemo />标签上。
如果没有给外层组件显式指定key,React会默认用数组下标index作为key。当你在表格头部增删行时,所有行的index都会整体偏移,React会错误地复用组件实例,给原本对应第N行的组件传入第N+1行的props,自然会触发所有行的重渲染。
这也正好对应你观察到的现象:尾部增行时前面所有行的index不变,所以没有额外重渲染;头部增行时所有行index偏移,触发全量重渲染。
修复方案:调整key的位置
myRows.map((row, rowIndex) => <RowMemo key={row.id} {...{ row, rowIndex }} /> )
注意:不需要再在组件内部的tr上重复写key。
2. 删除行的逻辑存在参数命名冲突
你当前的删除逻辑里,filter的回调参数名和外层要删除的row变量重名,导致内层的row变量覆盖了外层的目标行变量,row != row的条件永远为false,会直接清空整个表格数组,属于明显的语法错误。
修复方案:修改参数名避免冲突
function removeTableProgramFormList(e, targetRow) { setTableProgramFormList(prevState => prevState.filter(row => row !== targetRow)); }
如果你的业务场景中row对象的引用可能变化,可以改用id做判断:
function removeTableProgramFormList(e, targetRow) { setTableProgramFormList(prevState => prevState.filter(row => row.id !== targetRow.id)); }
3. 可选优化:简化memo比较逻辑
你当前的比较逻辑是直接对比row的引用,只要你操作数组时保持未修改的row引用不变(比如用filter、slice等immutable方法返回新数组,不修改原数组元素),这个逻辑是完全可用的。如果需要更轻量化的对比,可以调整为只对比row.id:
function compare(prev, next) { return prev.row.id === next.row.id && prev.rowIndex === next.rowIndex; }
内容的提问来源于stack exchange,提问作者Victor Gorban
相关产品推荐
相关产品推荐

