React 使用循环生成的数组作为初始值时输入框值不更新如何解决
问题原因
你遇到的输入框值不同步的问题是由以下4个错误共同导致的:
- 事件处理函数调用逻辑不匹配:
updateKernel定义为返回函数的高阶函数,但你在onChange中调用时没有执行返回的更新逻辑,导致状态更新代码从未运行 - 数组拷贝不完整:仅对
kernel做了外层浅拷贝,内层数组仍然是原状态的引用,不符合React不可变数据的更新原则,存在状态更新检测隐患 - key属性不稳定:渲染时用
value作为key的一部分,值修改后key变化导致React直接重建输入框,丢失已输入内容 - 类型不统一:range输入的
e.target.value是字符串类型,和内核中存储的数字类型混用,容易出现隐式转换异常
修复代码
1. 修正handleKernel的类型转换
const handleKernel = (e) => { // 转换为数字类型,避免字符串和数字混用 const size = Number(e.target.value) setKernelSize(size) const newKernel = [] for (let i = 0; i < size; i++) { newKernel.push([]) for (let j = 0; j < size; j++) { newKernel[i].push(1) } } setKernel(newKernel) }
2. 修正updateKernel的逻辑
去掉多余的闭包返回,同时完整拷贝内核数组:
const updateKernel = (e, rowIndex, colIndex) => { // 输入值转数字,保持类型统一 const inputVal = Number(e.target.value) // 内层外层都做拷贝,避免修改原状态引用 const kernelCopy = kernel.map(row => [...row]) kernelCopy[rowIndex][colIndex] = inputVal setKernel(kernelCopy) }
3. 修正渲染部分的key属性
使用稳定的行列索引组合作为key,避免元素重建:
{ kernel.map((row, rowIndex) => { return ( <div className="row mt-3" key={`row_${rowIndex}`}> { row.map((cell, colIndex) => { return ( <div className="input-wrap" key={`cell_${rowIndex}_${colIndex}`}> <input type="text" className="form-control" value={cell} onChange={(e) => updateKernel(e, rowIndex, colIndex)} /> </div> ) }) } </div> ) })}
可选写法:如果你希望保留
updateKernel的高阶函数写法,可以做如下修改,就不用在onChange里多写一层箭头函数:// 定义时先收行列参数,返回接收事件的函数 const updateKernel = (rowIndex, colIndex) => (e) => { const inputVal = Number(e.target.value) const kernelCopy = kernel.map(row => [...row]) kernelCopy[rowIndex][colIndex] = inputVal setKernel(kernelCopy) } // 调用时直接传行列参数即可 <input type="text" className="form-control" value={cell} onChange={updateKernel(rowIndex, colIndex)} />
内容的提问来源于stack exchange,提问作者M Muqiit Faturrahman
相关产品推荐
相关产品推荐

