React中AddItem模态框提交数据成功后无法关闭问题排查
问题根因
模态框无法关闭的核心原因是页面同时渲染了两个完全独立的AddItem组件实例,两个实例的props不互通:
- 第一个实例写在
NewInvoice.js的Button标签内,受itemOpen状态控制显隐,只传入了setitemOpen方法,没有传入往表格新增行的func方法,即使提交数据也无法写入表格。 - 第二个实例硬编码在
FormDataTable.js的返回结构中,默认常驻渲染不受状态控制,只传入了新增行的func方法,没有传入setitemOpen方法。
你之前交互的一直是第二个常驻的AddItem实例:它能正常调用func把数据写入表格,但是执行props.setitemOpen(false)时会直接触发setitemOpen is not a function的报错,根本无法修改控制显隐的状态,模态框自然无法关闭。
顺带一提你代码里还有个小问题:表格表头顺序和行内容渲染顺序不匹配,会导致列数据错位。
修复方案
- 删除
FormDataTable.js中硬编码的<AddItem func={addRows}/>代码,移除多余的常驻模态框实例。 - 将表格数据状态从
FormDataTable提升到父组件NewInvoice中管理,让受控的AddItem实例同时拿到新增数据、关闭模态框两个方法。
修正后代码参考
NewInvoice.js
const [itemOpen, setitemOpen] = useState(false); // 提升表格数据状态到父组件 const [tableData, setTableData] = useState([]); // 新增行方法移到父组件 const addRows = (data) => { const totalData = tableData.length; data.id = totalData + 1; setTableData([...tableData, data]); }; return ( <> <div className="new-invoice-client"> {/* 把表格数据传给子组件渲染 */} <FormDataTable tableData={tableData}/> </div> <div className="new-item-links" style={{ marginLeft: "35px", marginTop: "35px" }} > <Button onClick={() => setitemOpen(true)}> <BsPlus /> Add an Item {/* 受控模态框同时传入两个方法 */} {itemOpen && <AddItem setitemOpen={setitemOpen} func={addRows} />} </Button> </div> </> )
FormDataTable.js
function FormDataTable(props) { // 移除本地tableData状态和addRows方法、移除多余的AddItem实例 const tableRows = props.tableData.map((value, index) => { return ( <tr key={index}> {/* 对齐表头顺序 */} <td>{value.item}</td> <td>{value.description}</td> <td>{value.quantity}</td> <td>{value.rate}</td> <td>{value.amount}</td> </tr> ); }); return ( <React.Fragment> <table className="table"> <thead> <tr> <th>Item</th> <th>Description</th> <th>Qty</th> <th>Rate</th> <th>Amount</th> </tr> </thead> <tbody>{tableRows}</tbody> </table> </React.Fragment> ); }
可选优化
AddItem组件中注释掉的clearState()方法可以在提交逻辑中放开,保存成功后清空表单输入,下次打开模态框不会残留上次的填写内容:
const handleSubmit = (event) => { event.preventDefault(); const formInputData = {item, amount, rate, quantity, description}; props.func(formInputData); clearState(); // 放开清空表单逻辑 props.setitemOpen(false); };
内容的提问来源于stack exchange,提问作者user23424
相关产品推荐
相关产品推荐

