You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FormData提交多条API数据时仅能获取单条数据的问题

问题:FormData提交多条记录时仅能获取最后一条数据

通过API获取到包含sequence为1和2的两条记录,渲染成可编辑表单后提交,FormData中仅存在sequence为2的数据,无法将全部记录传入updateAPDB接口完成更新。


核心原因

表单中所有同类型输入框的name属性完全重复,FormData收集数据时,相同name的字段会被最后一个元素的值覆盖,最终只能保留最后一条记录的内容。


解决方案

步骤1:给输入框添加唯一标识的name

基于每条记录的acd_con_seq(唯一序列值),给每个输入框的name添加后缀,确保字段名唯一,比如applicationId_1、applicationId_2。

步骤2:在action中整理数据结构

将FormData中的零散字段重新组合成数组格式,匹配原有的多条记录结构,再传给更新接口。


修改后的代码示例

表单渲染代码

<div className="APDB_table-wrapper">
  <table className="table-Result">
    <tbody>
      <tr className="table-Result-Row">
        <th className="table-Result-Header">Application ID</th>
        <th className="table-Result-Header">Application Name</th>
        <th className="table-Result-Header">GSID</th>
        <th className="table-Result-Header">Sequence</th>
        <th className="table-Result-Header">Application DL</th>
        <th className="table-Result-Header">Manager DL</th>
        <th className="table-Result-Header">
          Application Owner DL
        </th>
        <th className="table-Result-Header">DataCenter</th>
        <th className="table-Result-Header">QA SFTP ID</th>
        <th className="table-Result-Header">QA Password</th>
        <th className="table-Result-Header">PROD SFTP ID</th>
        <th className="table-Result-Header">PROD Password</th>
        <th className="table-Result-Header">Updated User</th>
      </tr>
      {Result.map((item) => (
        <tr key={item.acd_con_seq} className="table-Result-Data">
          <td>
            <input
              type="text"
              name={`applicationId_${item.acd_con_seq}`}
              value={item.acd_ap_id}
              readOnly
            />
          </td>
          <td>
            <input
              type="text"
              name={`applicationName_${item.acd_con_seq}`}
              value={item.acd_ap_nm}
              readOnly
            />
          </td>
          <td>
            <input
              type="text"
              name={`gsid_${item.acd_con_seq}`}
              value={item.acd_ap_gsid}
              readOnly
            />
          </td>
          <td>
            <input
              type="text"
              name={`Sequence_${item.acd_con_seq}`}
              value={item.acd_con_seq}
              readOnly
            />
          </td>
          <td>
            <input
              type="text"
              name={`applicationDl_${item.acd_con_seq}`}
              onChange={(e) => {
                item.acd_appl_dl = e.target.value;
              }}
              defaultValue={item.acd_appl_dl}
            />
          </td>
          <td>
            <input
              type="email"
              name={`leadManagerDl_${item.acd_con_seq}`}
              defaultValue={item.acd_lead_manager_dl}
              onChange={(e) => {
                item.acd_lead_manager_dl = e.target.value;
              }}
            />
          </td>
          <td>
            <input
              type="email"
              name={`systemOwnerNameDl_${item.acd_con_seq}`}
              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_${item.acd_con_seq}`}
              defaultValue={item.acd_dc_name}
              onChange={(e) => {
                item.acd_dc_name = e.target.value;
              }}
            />
          </td>
          <td>
            <input
              type="text"
              name={`qaSftpId_${item.acd_con_seq}`}
              defaultValue={item.acd_qa_sftp_id}
              onChange={(e) => {
                item.acd_qa_sftp_id = e.target.value;
              }}
            />
          </td>
          <td>
            <input
              type="text"
              name={`qaSftpPwd_${item.acd_con_seq}`}
              defaultValue={item.acd_qa_sftp_pwd}
              onChange={(e) => {
                item.acd_qa_sftp_pwd = e.target.value;
              }}
            />
          </td>
          <td>
            <input
              type="text"
              name={`prodSftpId_${item.acd_con_seq}`}
              defaultValue={item.acd_prod_sftp_id}
              onChange={(e) => {
                item.acd_prod_sftp_id = e.target.value;
              }}
            />
          </td>
          <td>
            <input
              type="text"
              name={`prodSftpPwd_${item.acd_con_seq}`}
              defaultValue={item.acd_prod_sftp_pwd}
              onChange={(e) => {
                item.acd_prod_sftp_pwd = e.target.value;
              }}
            />
          </td>
          <td>
            <input
              type="text"
              name={`updatedUser_${item.acd_con_seq}`}
              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" />
</div>
</Form>

表单提交action函数

export async function action({ request }) {
  console.log("function called");
  const formData = await request.formData();
  const formEntries = Array.from(formData.entries());
  
  // 整理成数组格式的记录
  const records = {};
  formEntries.forEach(([key, value]) => {
    // 拆分字段名和sequence
    const [fieldName, seq] = key.split("_");
    if (!records[seq]) {
      records[seq] = {};
    }
    // 映射回原数据字段名
    switch(fieldName) {
      case "applicationId":
        records[seq].acd_ap_id = value;
        break;
      case "applicationName":
        records[seq].acd_ap_nm = value;
        break;
      case "gsid":
        records[seq].acd_ap_gsid = value;
        break;
      case "Sequence":
        records[seq].acd_con_seq = value;
        break;
      case "applicationDl":
        records[seq].acd_appl_dl = value;
        break;
      case "leadManagerDl":
        records[seq].acd_lead_manager_dl = value;
        break;
      case "systemOwnerNameDl":
        records[seq].acd_system_owner_name_dl = value;
        break;
      case "dataCenterName":
        records[seq].acd_dc_name = value;
        break;
      case "qaSftpId":
        records[seq].acd_qa_sftp_id = value;
        break;
      case "qaSftpPwd":
        records[seq].acd_qa_sftp_pwd = value;
        break;
      case "prodSftpId":
        records[seq].acd_prod_sftp_id = value;
        break;
      case "prodSftpPwd":
        records[seq].acd_prod_sftp_pwd = value;
        break;
      case "updatedUser":
        records[seq].acd_upd_usr = value;
        break;
      default:
        break;
    }
  });
  
  // 转换成数组传给接口
  const dataArray = Object.values(records);
  console.log(dataArray);
  
  const newData = await updateAPDB(dataArray);
  if (newData !== "1") {
    return null;
  } else {
    return redirect(`/webpage`);
  }
}

可选优化:数组式命名

如果使用React Hook Form、Remix等支持表单数组的框架,可直接用数组格式的name,比如:

<input
  type="text"
  name={`records[${index}].applicationId`}
  value={item.acd_ap_id}
  readOnly
/>

这种方式下FormData会自动整理成数组结构,action中无需手动拆分字段,直接解析即可。


内容的提问来源于stack exchange,提问作者user23154524

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:23:11