表单提交仅获取最后一条数组对象数据的问题及解决方法
问题描述
我从API获取多条数据,通过map渲染成带可编辑输入框的表格,期望用户修改后提交所有变更给API更新。但提交表单时只能获取到Result中最后一条记录的值,无法拿到全部数据。当前渲染代码和表单处理代码如下:
渲染表格的代码
{Result.map((item,index) => ( <tr key={index} className="table-Result-Data"> <td> <input type="text" name="applicationId" value={item.acd_ap_id} readOnly /> </td> <td> <input type="text" name="applicationName" value={item.acd_ap_nm} readOnly /> </td> <td> <input type="text" name="gsid" value={item.acd_ap_gsid} readOnly /> </td> <td> <input type="text" name="Sequence" value={item.acd_con_seq} readOnly /> </td> <td> <input type="text" name="applicationDl" onChange={(e) => { item.acd_appl_dl = e.target.value; }} defaultValue={item.acd_appl_dl} /> </td> <td> <input type="email" name="leadManagerDl" defaultValue={item.acd_lead_manager_dl} onChange={(e) => { item.acd_lead_manager_dl = e.target.value; }} /> </td> <td> <input type="email" name="systemOwnerNameDl" defaultValue={item.acd_system_owner_name_dl} onChange={(e) => { item.acd_system_owner_name_dl = e.target.value; }} /> </td> <td> <input type="text" name="dataCenterName" defaultValue={item.acd_dc_name} onChange={(e) => { item.acd_dc_name = e.target.value; }} /> </td> <td> <input type="text" name="qaSftpId" defaultValue={item.acd_qa_sftp_id} onChange={(e) => { item.acd_qa_sftp_id = e.target.value; }} /> </td> <td> <input type="text" name="qaSftpPwd" defaultValue={item.acd_qa_sftp_pwd} onChange={(e) => { item.acd_qa_sftp_pwd = e.target.value; }} /> </td> <td> <input type="text" name="prodSftpId" defaultValue={item.acd_prod_sftp_id} onChange={(e) => { item.acd_prod_sftp_id = e.target.value; }} /> </td> <td> <input type="text" name="prodSftpPwd" defaultValue={item.acd_prod_sftp_pwd} onChange={(e) => { item.acd_prod_sftp_pwd = e.target.value; }} /> </td> <td> <input type="text" name="updatedUser" defaultValue={item.acd_upd_usr} onChange={(e) => { item.acd_upd_usr = e.target.value; }} /> </td> </tr> ))} </tbody> </table> </div> <input type="submit" className="submit_Update" />
表单处理代码
export async function action({ request }) { console.log(" APDB functioncalled"); const formData = await request.formData(); console.log(formData) const data = Object.fromEntries(formData); console.log(data) }
问题原因
不是map函数导致的问题,核心原因有两个:
- 输入框name属性重复:所有行的同类型输入框使用了相同的name(比如
applicationId、applicationDl),表单提交时,同名的输入值会被覆盖,最终只保留最后一行的输入值。 - 直接修改原数据不符合React规范:直接修改API返回的
item对象,这种方式不会触发组件重新渲染,无法准确跟踪所有数据的变更状态,同时也会导致表单提交时无法正确收集所有行的数据。
解决方案
方案一:修改输入框name属性为数组格式(适合原生表单提交)
给每个输入框的name添加行索引,使用数组格式命名,表单提交时会自动将所有行的数据整理为数组结构:
{Result.map((item, index) => ( <tr key={index} className="table-Result-Data"> <td> <input type="text" name={`records[${index}].applicationId`} value={item.acd_ap_id} readOnly /> </td> <td> <input type="text" name={`records[${index}].applicationName`} value={item.acd_ap_nm} readOnly /> </td> {/* 其他输入框同理,修改name为`records[${index}].字段名`格式 */} <td> <input type="text" name={`records[${index}].applicationDl`} defaultValue={item.acd_appl_dl} onChange={(e) => { item.acd_appl_dl = e.target.value; }} /> </td> {/* 剩余输入框重复上述修改 */} </tr> ))}
此时在action函数中,可以用qs库解析formData,直接得到所有行的数组:
import qs from 'qs'; export async function action({ request }) { const formData = await request.formData(); const parsedData = qs.parse(formData.toString()); console.log(parsedData.records); // 所有行的完整数据数组 }
方案二:使用React状态管理表格数据(推荐,符合React状态驱动理念)
将API返回的Result存入组件状态,通过状态更新跟踪数据变更,提交时直接将状态数据发送给API:
- 初始化状态:
import { useState, useEffect } from 'react'; function YourComponent() { const [tableData, setTableData] = useState([]); useEffect(() => { // 模拟API请求获取数据 const fetchData = async () => { const res = await fetch('/your-api-url'); const result = await res.json(); setTableData(result); }; fetchData(); }, []);
- 渲染受控输入框:
将输入框改为受控组件,绑定状态值,onChange时更新对应行的数据:
{tableData.map((item, index) => ( <tr key={index} className="table-Result-Data"> <td> <input type="text" value={item.acd_ap_id} readOnly /> </td> <td> <input type="text" value={item.acd_appl_dl} onChange={(e) => { setTableData(prev => { const newData = [...prev]; newData[index] = { ...newData[index], acd_appl_dl: e.target.value }; return newData; }); }} /> </td> {/* 其他输入框同理,替换value和onChange逻辑 */} </tr> ))}
- 提交数据:
提交时直接将tableData作为请求体发送给API:
const handleSubmit = async () => { const res = await fetch('/your-update-api', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(tableData) }); const result = await res.json(); // 处理提交结果 }; // 替换原submit按钮 <button type="button" className="submit_Update" onClick={handleSubmit}>提交</button>
总结
优先选择方案二,它符合React状态驱动的设计理念,能更准确地跟踪数据变更,也避免了表单name属性冲突的问题。如果必须使用原生表单提交,则采用方案一,通过修改name属性格式确保所有行的数据被正确收集。
内容的提问来源于stack exchange,提问作者user23154524
相关产品推荐
相关产品推荐

