如何在React Router路由的action函数中获取非受控多选Autocomplete的值?
解决React Router Form中Material UI多选Autocomplete值无法提交的问题
问题根源在于Material UI的Autocomplete(多选模式)并非原生表单控件,它不会自动将选中的值同步到表单的formData中——你看到的内部TextField只是负责展示输入状态,实际选中的标签数组并不会被作为表单字段提交。
下面提供两种可行的解决方式:
方式一:受控状态 + 隐藏Input
通过组件状态管理选中的标签,再用隐藏的原生input字段将值传递给formData:
import { useState } from 'react'; import { Form } from 'react-router-dom'; import { TextField, Autocomplete, Button } from '@mui/material'; export async function action({ request }) { const formData = await request.formData(); const newPost = Object.fromEntries(formData); // 将逗号分隔的字符串还原为数组 newPost.tags = newPost.tags ? newPost.tags.split(',') : []; // 后续处理逻辑 } export default function NewPost() { const [selectedTags, setSelectedTags] = useState([]); return ( <Form method="post"> <TextField name="title" label="标题" fullWidth margin="normal" /> <TextField name="body" label="正文" fullWidth margin="normal" multiline rows={4} /> <Autocomplete multiple options={[1, 2, 3, 4, 5]} value={selectedTags} onChange={(event, newValue) => setSelectedTags(newValue)} renderInput={(params) => ( <TextField {...params} label="标签" fullWidth margin="normal" /> )} /> {/* 隐藏input,用于提交选中的标签 */} <input type="hidden" name="tags" value={selectedTags.join(',')} /> <Button type="submit" variant="contained" color="primary" style={{ marginTop: 16 }}> 创建文章 </Button> </Form> ) }
方式二:手动构建FormData提交
利用React Router的useSubmit钩子,在提交时手动将选中的标签加入formData:
import { useState, useCallback } from 'react'; import { Form, useSubmit } from 'react-router-dom'; import { TextField, Autocomplete, Button } from '@mui/material'; export async function action({ request }) { const formData = await request.formData(); const newPost = { title: formData.get('title'), body: formData.get('body'), tags: JSON.parse(formData.get('tags')), }; // 后续处理逻辑 } export default function NewPost() { const [selectedTags, setSelectedTags] = useState([]); const submit = useSubmit(); const handleSubmit = useCallback((event) => { event.preventDefault(); const formData = new FormData(event.currentTarget); // 将标签数组转为JSON字符串存入formData formData.set('tags', JSON.stringify(selectedTags)); submit(formData, { method: 'post' }); }, [selectedTags, submit]); return ( <Form onSubmit={handleSubmit}> <TextField name="title" label="标题" fullWidth margin="normal" /> <TextField name="body" label="正文" fullWidth margin="normal" multiline rows={4} /> <Autocomplete multiple options={[1, 2, 3, 4, 5]} value={selectedTags} onChange={(event, newValue) => setSelectedTags(newValue)} renderInput={(params) => ( <TextField {...params} label="标签" fullWidth margin="normal" /> )} /> <Button type="submit" variant="contained" color="primary" style={{ marginTop: 16 }}> 创建文章 </Button> </Form> ) }
两种方式的核心都是手动关联选中的标签值与表单提交数据,因为Autocomplete不会自动完成这个过程。
内容的提问来源于stack exchange,提问作者Ioannis Potouridis
相关产品推荐
相关产品推荐

