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

React Router v6中用Form与Actions实现动态输入字段的问题

解决react-router-dom动态表单字段的两个问题

问题分析

  • 提交后仅获取单个兴趣:所有兴趣输入框的name属性都是val,FormData中同名键只会保留最后一次输入值,无法收集数组。
  • uncontrolled输入警告:添加新字段时,对象属性是name和age,但输入框绑定的是item.val,初始值为undefined,导致输入从无控转为受控。

修改后的完整代码

import { Form } from "react-router-dom";
import { useState } from "react";

export const action = async ({ request }) => {
  const formData = await request.formData();
  // 手动提取数组类型的表单字段
  const data = {
    username: formData.get("username"),
    password: formData.get("password"),
    interest: formData.getAll("interest[]") // 用getAll获取所有同名值组成数组
  };
  console.log(data);
  return data;
};

export default function Home() {
  const [interests, setInterests] = useState([{ val: "" }]);

  const handleFormChange = (event, index) => {
    let data = [...interests];
    data[index].val = event.target.value; // 直接赋值val,不用取name,因为输入框name是给FormData用的
    setInterests(data);
  };

  const addFields = () => {
    // 添加和初始结构一致的对象,避免undefined值
    setInterests([...interests, { val: "" }]);
  };

  const removeFields = (index) => {
    let data = [...interests];
    data.splice(index, 1);
    setInterests(data);
  };

  return (
    <div>
      <Form method="post" className="form">
        <input type="text" name="username" placeholder="username" />
        <input type="password" name="password" placeholder="password" />
        {interests.map((item, index) => (
          <div key={index}>
            <input
              type="text"
              name="interest[]" // 改成带[]的name,让FormData识别为数组
              placeholder="interests"
              onChange={(event) => handleFormChange(event, index)}
              value={item.val}
            />
            <button type="button" onClick={() => removeFields(index)}>Remove</button>
          </div>
        ))}
        <button type="button" onClick={addFields}>Add More..</button>
        <button type="submit">Submit</button>
      </Form>
    </div>
  );
}

关键改动说明

  1. 表单字段命名:将兴趣输入框的name改为interest[],这样FormData会把所有该名称的输入值收集为集合,后续用getAll方法就能拿到完整数组。
  2. 修复uncontrolled警告:addFields中添加的对象改为{ val: "" },确保每个输入框的value初始值为字符串,避免undefined导致的状态切换。
  3. FormData处理优化:不再用Object.fromEntries直接转换,而是手动提取字段,对数组类型的字段使用formData.getAll()获取所有值,保证interest是数组格式。
  4. 简化change事件处理:因为输入框的name是给FormData用的,状态更新时直接赋值val属性即可,无需通过event.target.name动态获取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:36:30