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

如何结合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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:15:01