React:MUI Autocomplete开启multiple后结合react-hook-form Controller失效
解决react-hook-form Controller与MUI Autocomplete(多选)值绑定异常问题
问题重现
使用react-hook-form的<Controller>控制MUI <Autocomplete>(多选模式)时,表单提交后rooms字段始终返回0,而非预期的选中选项数组。例如选择Bathroom(value:1)和Kitchen(value:0),实际得到rooms: 0,预期应为rooms: [{label: 'Bathroom', value: 1}, {label: 'Kitchen', value: 0}]。
使用包版本:
- react-hook-form(7.43.9)
- @material-ui/core(4.12.4)
原代码:
<Controller control={control} name="rooms" render={({ field }) => ( <Autocomplete multiple limitTags={6} // data is formatted like this: [{label: string, value: number}] options={data} filterSelectedOptions style={{ minWidth: '350px', maxWidth: '30%' }} renderInput={params => ( <TextField {...params} variant="outlined" label="Rooms" placeholder="Search" /> )} {...field} /> )} />
问题原因
直接展开{...field}会导致Autocomplete的value和onChange与react-hook-form的字段逻辑不兼容:
- Autocomplete多选模式下,
onChange的第二个参数是选中的选项数组,但field.onChange默认的参数处理逻辑无法正确识别这个数组,导致值被错误解析为单个数值(最后选中项的value)。 field.value的传递方式没有适配Autocomplete的多选值格式。
解决方案
手动绑定Autocomplete的value和onChange,适配react-hook-form的字段逻辑:
修正后的代码
// 首先确保useForm初始化时设置默认值为空数组 const { control, handleSubmit } = useForm({ defaultValues: { rooms: [] } }); // Controller组件部分 <Controller control={control} name="rooms" render={({ field }) => ( <Autocomplete multiple limitTags={6} options={data} filterSelectedOptions style={{ minWidth: '350px', maxWidth: '30%' }} // 手动绑定value,确保与field值同步 value={field.value} // 自定义onChange,将选中的选项数组直接传给field.setValue onChange={(event, newValue) => field.setValue(newValue)} renderInput={params => ( <TextField {...params} variant="outlined" label="Rooms" placeholder="Search" /> )} // 保留field的ref属性,确保表单校验等逻辑正常 ref={field.ref} /> )} />
关键说明
- 设置默认值:在
useForm的defaultValues中给rooms设置空数组,避免初始值为undefined导致Autocomplete渲染异常。 - 手动绑定value:明确将
field.value传给Autocomplete的value,确保选中状态与表单字段值同步。 - 自定义onChange:直接将Autocomplete返回的选中选项数组
newValue传给field.setValue,让react-hook-form正确接收数组格式的值。 - 保留ref:将
field.ref传给Autocomplete,确保react-hook-form的表单校验、字段注册等逻辑正常工作。
额外检查点
- 确认
data数组的格式严格为[{label: string, value: number}],Autocomplete需要通过label显示选项,value作为唯一标识。 - 若只需提交选项的value数组而非完整对象,可在
onChange中转换后再传入:onChange={(event, newValue) => { const valueList = newValue.map(item => item.value); field.setValue(valueList); }}
内容的提问来源于stack exchange,提问作者Boris
相关产品推荐
相关产品推荐

