React中动态创建三维矩阵输入框时添加行失败,求排查错误
动态输入框添加行按钮失效问题分析
问题描述
我尝试创建动态输入框,输入框结构为三维矩阵mat[m][n][2]。底部按钮用于添加新的二维矩阵,每个矩阵末尾的按钮用于添加新行。但点击添加行按钮时功能失效,请问我在添加特定矩阵行时犯了什么错误?
代码示例
const Counter = () => { const [info,setInfo] = useState([]); const addNewCond = (e) => { let matrix = [["",""]]; setInfo([...info,matrix]); } const addNewDetailedCond = (index) => (e) => { let matrix=info[index]; matrix.push(["",""]); setInfo(matrix); } const deleteCond = (e) => { } const deleteDetailedCond = (index) => e => {} const handleDetailedCond = (i,j,k) => (e) => {} return ( <div> <form className="form-horizontal form-label-left"> { info.map((mat,i) => ( <> { mat.map((rows,j) => ( <div className="form-group"> <div className="col-md-6 col-sm-6"> <select className="form-control" value={info[i][j][0]} onChange={handleDetailedCond(i,j,0)}> <option value="test">Test</option> </select> </div> <div className="col-md-6 col-sm-6"> <input className="form-control" value={info[i][j][1]} onChange={handleDetailedCond(i,j,1)}/> </div> </div> )) } { mat.length !== 0 ? <button className="btn btn-primary" type="button" onClick={addNewDetailedCond(i)}>Add New Detailed Info</button> : null } </> )) } <div className="form-group"> <div className="col-md-6 col-sm-6"> <button type="button" className="btn btn-primary" onClick={addNewCond}>Add New Condition</button> </div> </div> </form> </div> ) }
错误原因及修复方案
核心错误
直接修改原状态+破坏状态结构
你在addNewDetailedCond里直接取出info[index]并执行push,这属于直接修改React状态的操作,React无法感知到这种数据变化。更严重的是,最后调用setInfo(matrix)时,把单个二维矩阵当成了整个三维状态数组传入,直接将info从[二维数组, 二维数组...]的结构变成了单个二维数组,彻底破坏了状态的层级结构。未使用函数式更新获取最新状态
当新状态依赖旧状态时,应该采用函数式更新的方式,避免闭包导致获取到过期的状态值。
修复后的addNewDetailedCond函数
const addNewDetailedCond = (index) => (e) => { setInfo(prevInfo => { // 复制整个状态数组,避免修改原数据 const updatedInfo = [...prevInfo]; // 复制目标二维矩阵并添加新行 updatedInfo[index] = [...updatedInfo[index], ["", ""]]; return updatedInfo; }); }
额外优化
给map渲染的元素添加唯一key属性,避免React渲染时出现异常:
info.map((mat,i) => ( <div key={i}> { mat.map((rows,j) => ( <div className="form-group" key={j}> {/* 原有输入框/选择框内容 */} </div> )) } {/* 原有添加行按钮 */} </div> ))
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

