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

react-hook-form中如何根据兄弟组件状态重置select选择器的值

问题核心原因

  1. 违反React Hook调用规则:你在Controller的render回调的onChange属性中直接声明useEffect,Hook只能在React组件顶层调用,放在回调函数中既不会按预期触发,也会触发Hook规则校验错误。
  2. 状态多源不同步:你同时维护了react-hook-form(以下简称RHF)的表单字段状态,和自己声明的selectedYear/selectedMonth本地状态,修改本地状态不会同步到RHF的表单数据源,所以绑定了field的选择组件不会响应变化。
  3. 组件属性书写错误:SelectBirthMonth中Listbox的value属性误写为比较表达式,返回布尔值而非预期的月份选项对象。

解决方案

RHF修改绑定了Controller的字段值,直接使用useForm返回的setValue方法即可,不需要额外维护本地状态,以RHF的表单状态为唯一数据源即可。

第一步:父组件调整

首先从useForm中取出watch和setValue方法,直接监听年数字段变化:

// 父组件内的useForm调用
const { control, watch, setValue } = useForm({
  defaultValues: {
    selectedBirthYear: years[0],
    selectedBirthMonth: months[0]
  }
});
// 直接监听RHF的年数字段变化,不需要自己声明selectedYear state
const selectedBirthYear = watch('selectedBirthYear');

简化两个Controller的写法,删除错误的内联useEffect:

{/* 年份选择Controller */}
<Controller
   control={control}
   name="selectedBirthYear"
   render={({ field }) => (
     <SelectBirthYear
       field={field}
       years={years}
    />
   )}
/>

{/* 月份选择Controller */}
<Controller
   control={control}
   name="selectedBirthMonth"
   render={({ field }) => (
     <SelectBirthMonth
       field={field}
       startYear={startYear}
       selectedYear={selectedBirthYear}
       months={months}
       reducedMonths={reducedMonths}
    />
   )}
/>

在父组件内添加监听逻辑,年份变化时直接用setValue修改月份字段的表单值:

useEffect(() => {
  if(Number(selectedBirthYear.name) === startYear){
    const targetMonth = reducedMonths[reducedMonths.length - 1];
    // 直接修改RHF的表单值,会自动同步到所有绑定了该字段的组件
    setValue('selectedBirthMonth', targetMonth, {
      shouldValidate: true, // 需联动校验可开启
      shouldDirty: true // 需标记字段为已修改可开启
    });
  }
}, [selectedBirthYear, startYear, reducedMonths, setValue]);

第二步:调整SelectBirthMonth组件

删除组件内冗余的本地状态相关逻辑,修正Listbox的value属性错误:

export const SelectBirthMonth = ({
  startYear,
  selectedYear,
  months,
  field,
  reducedMonths}) => {
  const { onChange, value } = field;

  return (
    {/* 修正value属性的错误写法,直接取field.value即可,RHF会自动同步 */}
    <Listbox value={value} onChange={onChange}>
      {({ open }) => (
        <>
          <Listbox.Label className="block text-sm font-medium text-gray-700">Geburtsmonat</Listbox.Label>
          <div className="mt-1 relative">
            <Listbox.Button className="bg-white relative w-full border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-yellow-500 focus:border-yellow-500 sm:text-sm">
              <span className="block truncate">{value?.name}</span>
              <span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
                <SelectorIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
              </span>
            </Listbox.Button>

            <Transition
              show={open}
              as={Fragment}
              leave="transition ease-in duration-100"
              leaveFrom="opacity-100"
              leaveTo="opacity-0"
            >
              <Listbox.Options
                static
                className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
              >
                { Number(selectedYear.name) == startYear ? reducedMonths.map((month) => (
                  <ListboxOption
                    key={month.id}
                    value={month}
                    date={month.name}
                  >
                  </ListboxOption>
                )) : months.map((month) => (
                  <ListboxOption
                    key={month.id}
                    value={month}
                    date={month.name}
                  >
                  </ListboxOption>
                ))
              }
              </Listbox.Options>
            </Transition>
          </div>
        </>
      )}
    </Listbox>
  )
}

内容的提问来源于stack exchange,提问作者Katharina Schreiber

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 14:39:03