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

React Router中如何将本地state数据传递给Form action?

解决React Router中动态表单数据传递到Action的问题

下面提供三种可行方案,适配不同场景需求:

方案1:给动态输入框添加数组格式的name属性(原生表单兼容最佳)

利用原生FormData的数组命名规则,给每个动态生成的input设置name属性,提交时FormData会自动收集数据,无需额外处理本地状态:

const FormComponent = () => {
  const [items, setItems] = useState<Item[]>([
    { name: '', quantity: 1, price: 0 },
  ]);

  const handleItemChange = (
    index: number,
    field: keyof Item,
    value: Item[keyof Item]
  ) => {
    const newItems = [...items];
    newItems[index][field] = value;
    setItems(newItems);
  };

  const addItem = () => {
    setItems([...items, { name: '', quantity: 1, price: 0 }]);
  };

  return (
    <Form method="post">
      {/* 其他表单字段 */}
      <div>
        <h3>Items</h3>
        {items.map((item, index) => (
          <div key={index}>
            <label>
              Name:
              <input
                type='text'
                name={`items[${index}].name`}
                value={item.name}
                onChange={(e) => handleItemChange(index, 'name', e.target.value)}
                required
              />
            </label>
            <label>
              Quantity:
              <input
                type='number'
                name={`items[${index}].quantity`}
                value={item.quantity}
                onChange={(e) => handleItemChange(index, 'quantity', Number(e.target.value))}
                required
              />
            </label>
            <label>
              Price:
              <input
                type='number'
                name={`items[${index}].price`}
                value={item.price}
                onChange={(e) => handleItemChange(index, 'price', Number(e.target.value))}
                required
              />
            </label>
          </div>
        ))}
        <button type='button' onClick={addItem}>Add Item</button>
      </div>
      <button type="submit">提交</button>
    </Form>
  );
};

对应Action中解析FormData:

async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const items: Item[] = [];
  let index = 0;
  
  // 循环读取数组格式的表单数据
  while (formData.has(`items[${index}].name`)) {
    items.push({
      name: formData.get(`items[${index}].name`) as string,
      quantity: Number(formData.get(`items[${index}].quantity`)),
      price: Number(formData.get(`items[${index}].price`)),
    });
    index++;
  }

  // 发送到服务器
  await fetch('/api/your-endpoint', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ items }),
  });

  return json({ success: true });
}

方案2:手动构建FormData提交(简洁高效)

使用React Router的useSubmit钩子,在提交时手动将本地items状态添加到FormData:

import { Form, useSubmit } from 'react-router-dom';

const FormComponent = () => {
  const submit = useSubmit();
  const [items, setItems] = useState<Item[]>([
    { name: '', quantity: 1, price: 0 },
  ]);

  const handleItemChange = (
    index: number,
    field: keyof Item,
    value: Item[keyof Item]
  ) => {
    const newItems = [...items];
    newItems[index][field] = value;
    setItems(newItems);
  };

  const addItem = () => {
    setItems([...items, { name: '', quantity: 1, price: 0 }]);
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    // 将items序列化为JSON字符串存入FormData
    formData.append('items', JSON.stringify(items));
    submit(formData, { method: 'post' });
  };

  return (
    <Form onSubmit={handleSubmit}>
      {/* 其他表单字段和动态输入框部分不变 */}
      <button type="submit">提交</button>
    </Form>
  );
};

对应Action中解析:

async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const items = JSON.parse(formData.get('items') as string) as Item[];
  
  // 后续服务器请求逻辑
  return json({ success: true });
}

方案3:用隐藏input存储JSON字符串

在表单中添加隐藏input,实时同步items状态的JSON序列化结果:

const FormComponent = () => {
  const [items, setItems] = useState<Item[]>([
    { name: '', quantity: 1, price: 0 },
  ]);

  // ... 其他函数不变

  return (
    <Form method="post">
      {/* 隐藏字段存储items的JSON数据 */}
      <input
        type="hidden"
        name="items"
        value={JSON.stringify(items)}
      />
      {/* 其他表单字段和动态输入框部分 */}
      <button type="submit">提交</button>
    </Form>
  );
};

Action解析逻辑与方案2完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 03:27:24