React setState更新数组后map渲染的TextField无法正常重渲染问题
问题原因
- 违反React状态不可变规则:你直接修改了原有
franchises数组的内部属性,再将原数组引用传入setFranchises,React做状态浅比较时会判定状态无变化,不会触发完整重渲染。同时闭包会缓存上一次渲染的旧franchises值,导致每次输入都是在旧值基础上修改,最终表现为输入仅单个字符生效。 - 列表渲染未加唯一key:遍历
franchises渲染商户组件时没有设置唯一key属性,React的diff算法无法正确识别列表项的更新,也会导致渲染异常。 - FixableTextField属性写法存在隐患:你在TextField组件中先定义了
value={props.restAddress}再展开props,虽然当前场景下父组件传入的value会覆盖该错误值,但该写法容易出现字段赋值错乱。
修正代码
1. 修正MyPage中onChange的状态更新逻辑
onChange={(e) => { const newValue = e.target.value // 生成全新的数组,完全不修改原有状态 const newFranchises = franchises.map((item, index) => { if (index === i) { // 对应下标的对象也做浅拷贝 return { ...item, data: { ...item.data, storeName: newValue } } } return item }) setFranchises(newFranchises) }}
2. 给列表项添加唯一key
{franchises && franchises.map((v, i) => { // 优先用商户的唯一id作为key,没有的话暂时用index兜底 return (<React.Fragment key={v.id || i}> {/* 原有FixableTextField、AddressForm组件逻辑保持不变 */} </React.Fragment>) })}
3. 修正FixableTextField的属性写法
删除TextField上多余的value={props.restAddress},避免赋值冲突:
<TextField variant="outlined" disabled={!fixable} {...props} style={{ margin: `${marginTop}px ${marginSide}px`, width: `calc(100% - ${marginSide * 2}px)` }} ></TextField>
如果确实需要兼容restAddress字段,调整属性顺序明确优先级:
<TextField variant="outlined" disabled={!fixable} {...props} // 固定属性放在展开props之后,避免被传入的props覆盖 value={props.restAddress || props.value} style={{ margin: `${marginTop}px ${marginSide}px`, width: `calc(100% - ${marginSide * 2}px)` }} ></TextField>
内容的提问来源于stack exchange,提问作者Janghyup Lee
相关产品推荐
相关产品推荐

