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
相关产品推荐
相关产品推荐

