React数组状态更新时array.map内CrudPanel组件未重渲染问题
问题产生原因
两个问题叠加导致该异常:
- 列表项错误使用数组索引作为
key值:React的虚拟DOM diff逻辑依赖key判断组件是否为同一实例,当你新增、删除、排序列表数据时,相同索引位置的key值index+1没有变化,React会直接复用之前位置的CrudPanel组件实例,不会重新创建组件 - CrudPanel组件本身存在状态同步缺陷:组件内部大概率将首次传入的
record属性拷贝到了本地state中,编辑弹窗读取的是本地state存储的旧值,既没有直接使用父组件传入的最新props,也没有在props更新时同步刷新本地state,最终导致弹窗展示首次渲染绑定的旧数据。
修复方案
1. 替换列表key为数据唯一标识
禁止使用数组索引作为动态列表的key,改用每条Firebase记录自带的唯一主键rowdata.key作为key,保证每条数据和对应组件实例唯一绑定,修改后的表格主体代码如下:
<tbody> {this.state.tableData.map((rowdata, index) => { return ( <tr key={rowdata.key}> <td style={{textAlign:'center'}}>{index+1}</td> <td>{rowdata.key}</td> <td>{rowdata.data.Fullname}</td> <td>{rowdata.data.Phonenumber}</td> <td>{rowdata.data.dateofbirth}</td> <td><CrudPanel username={rowdata.key} record={rowdata.data}/></td> </tr> ) })} </tbody>
2. 修复CrudPanel内部状态同步逻辑
二选一即可:
- 优先方案:编辑弹窗的展示数据不要拷贝到本地state,直接使用父组件传入的
props.record值,从根源避免父子状态不一致问题 - 如果编辑场景需要临时修改表单值、不希望改动实时同步到父组件,就增加props变化监听逻辑,在传入的record更新时同步刷新本地表单状态。类组件可在
componentDidUpdate生命周期实现同步,参考代码:
componentDidUpdate(prevProps) { if (prevProps.record !== this.props.record) { this.setState({ editFormData: structuredClone(this.props.record) }) } }
如果是函数组件,可使用useEffect监听record变化,同步更新本地表单状态。
内容的提问来源于stack exchange,提问作者Hassaan Raza Now
相关产品推荐
相关产品推荐

