如何结合react-hook-form与react-select实现单选按钮与多输入组合表单
问题修复方案
核心问题根因
- 第一个问题(registrationTypes键值变化):你错误地将
Creatable的options属性绑定到了已选值field.value,输入的新内容会直接覆盖预设选项列表,导致原有常量被篡改 - 第二个问题(无法删除已输入内容):同时维护了react-hook-form表单状态和本地
selectedRadio两套状态,状态不同步导致Creatable的绑定逻辑失效,多选项默认的删除功能无法正常触发 - 额外问题:原生单选按钮没必要用
Controller包裹,register方法更适配原生输入,且你实现的单选逻辑存在状态不同步的问题
修复后的完整代码
import { useState, useEffect } from 'react' import styled from 'styled-components' import Creatable from 'react-select/creatable' import { Controller, useForm } from 'react-hook-form' import { ErrorRow } from '../util/FormStyles' import { FormRulesProps } from '../util/formRuleTypes' import FormError from './FormError' const registrationTypes = [ { label: '允许所有持链接的用户注册', value: 'radioOne', }, { label: '仅允许指定邮箱域名的用户注册:', value: 'radioTwo', }, { label: '仅允许持指定邀请码的用户注册:', value: 'radioThree' }, { label: '通过资格名单文件手动指定可注册用户', value: 'radioFour', }, ] const RegistrationEligibilty = () => { const { control, reset, handleSubmit, register, watch, formState: { errors }, } = useForm<any>({ // 初始化默认值 defaultValues: { radio: '', radioTwo: [], radioThree: [] } }) // 监听单选值变化,用于联动显示多输入框和清空对应字段 const selectedRadio = watch('radio') // 切换单选选项时清空对应多输入内容 useEffect(() => { reset({ radio: selectedRadio, radioTwo: [], radioThree: [] }) }, [selectedRadio, reset]) const onSubmit = (data: any) => { console.log(data) } return ( <RegistrationEligibiltyContainer> <form onSubmit={handleSubmit(onSubmit)}> <FormRow> <RadioWrapper> {registrationTypes.map((rt) => ( <RadioGroup key={rt.value}> <Radio {...register('radio')} type="radio" value={rt.value} /> <TextRow text={rt.label} style={{ paddingLeft: '10px' }} /> {selectedRadio === 'radioTwo' && rt.value === 'radioTwo' && ( <FormRow> <div style={{ width: '90%' }}> <Controller name={rt.value} control={control} render={({ field }) => ( <Creatable {...field} isMulti // 没有预设选项就传空数组,不要绑定field.value options={[]} value={field.value} placeholder="输入域名后按回车确认" // 处理多选项值格式,确保同步正确 onChange={(val) => field.onChange(val || [])} /> )} /> </div> </FormRow> )} {selectedRadio === 'radioThree' && rt.value === 'radioThree' && ( <FormRow> <div style={{ width: '90%' }}> <Controller name={rt.value} control={control} render={({ field }) => ( <Creatable {...field} isMulti options={[]} value={field.value} placeholder="输入邀请码后按回车确认" onChange={(val) => field.onChange(val || [])} /> )} /> </div> </FormRow> )} </RadioGroup> ))} </RadioWrapper> </FormRow> {/* 可添加重置按钮测试全局重置功能 */} <button type="button" onClick={() => reset()}>重置表单</button> <button type="submit">提交</button> </FormContent> </form> </RegistrationEligibiltyContainer> ) } export default RegistrationEligibilty
关键修改说明
- 移除了冗余的本地
selectedRadio状态,使用react-hook-form提供的watch方法监听单选字段值,全局只有一套表单状态,避免状态不同步问题 - 原生单选按钮改用
register绑定,符合react-hook-form的最佳实践:原生输入优先用register,第三方组件才用Controller - 修复
Creatable的options配置,没有预设选项时传空数组,不会再修改原有registrationTypes常量 - 新增
useEffect监听单选值变化,切换选项时自动清空两个多输入字段的内容,符合联动需求 - 补充
Creatable的onChange异常处理,值为空时默认传回空数组,避免报错 - 初始化表单时配置默认值,全局调用
reset方法时所有字段会自动清空,符合重置需求 Creatable多选项默认支持点击标签叉号、按退格键删除已输入内容,状态绑定正确后即可正常使用该功能
内容的提问来源于stack exchange,提问作者Demian Sims
相关产品推荐
相关产品推荐

