React-Hook-Form 控制器忽略 useEffect

React-Hook-Form Controller ignoring useEffect

我有两个组件,其中 selectBirthMonth 取决于 SelectBirthYear。这就是我使用 useEffect 来观察 selectedYear 变化的原因,这样我就可以在需要时更改 selectedMonth。

code sandbox

所以在控制器上下文中,我的组件如下所示

<Controller
   control={control}
   name="selectedBirthYear"
   defaultValue={years[0]}
   render={({ field }) => (
     <SelectBirthYear
       field={field}
       years={years}
       value={selectedYear}
       defaultValue={selectedYear}
       onChange={useEffect(() => {setSelectedYear(field.value)})}
    />
   )}
 />
</div>

和...

<Controller
       control={control}
       name="selectedBirthMonth"
       defaultValue={months[0]}
       render={({ field }) => (
         <SelectBirthMonth
           field={field}
           startYear={startYear}
           selectedYear={selectedYear}
           months={months}
           value={selectedMonth}
           defaultValue={selectedMonth}
           reducedMonths={reducedMonths}
           onChange={useEffect(() => setSelectedMonth(field.value))}
        />
       )}
     />

SelectBirthMonth 完全忽略了以下代码:

  const [selectedMonth, setSelectedMonth] = useState(months[0]);

  const watchYearChange = () => {
    if(Number(selectedYear.name) == startYear){
      setSelectedMonth(reducedMonths[reducedMonths.length - 1]);
    }
  };

  useEffect(() => watchYearChange(), [selectedYear]);

意思是,无论选择哪一年,月份都不会反应。我想念什么?

我建议使用像 date-fns 这样的小型日期库来处理与日期相关的事情。这是一个很棒的包,这里是 docs。如果将来需要,它也可以为您处理 i18n。

我在下面的 CodeSandbox 中使用了它,还纠正了一些问题:

  • 当您使用 RHF 时,您不需要为您的组件设置额外的状态,因为 RHF 会为您管理表单状态。
  • 如果你只用一个日期来表示整个生日,那就简单多了——这样你将始终拥有年、月、日的当前值,而不需要观察值或使用额外定义的状态

答案太简单了,无法工作,但确实如此。好几次我都在 post 和 上阅读这个 ,但无法真正理解我在哪里以及如何使用 setValue。正如我假设的那样,我的 select 的值并没有改变,即使我正在观察兄弟状态的变化。

所以我将 setValue 放入 useEffect 钩子中,其余保持不变:

  const monthSelect = (data) => {
    setSelectedMonth(months[data.id - 1]);
  };
  
  const watchYearChange = () => {
    if(Number(selectedYear.name) == startYear){
      setSelectedMonth(lastAvaliableMonth)
    }
  };

  useEffect(() => setValue('selectedBirthMonth', lastAvaliableMonth), [selectedYear]);

为了以防万一,这里有两个兄弟姐妹:

<Controller
  control={control}
  name="selectedBirthYear"
  defaultValue={years[0]}
  render={({ field }) => (
  <SelectBirthYear
     field={field}
     years={years}
     value={selectedYear}
     defaultValue={selectedYear}
     onChange={useEffect(() => {setSelectedYear(field.value)})}
   />
 )}
/>

...和

    <Controller
      control={control}
      name="selectedBirthMonth"
      defaultValue={selectedMonth}
      render={({ field }) => (
      < SelectBirthMonth 
          field={field}
          startYear={startYear}
          selectedYear={selectedYear}
          months={months}
          value={selectedMonth}
          reducedMonths={reducedMonths}
          onChange={useEffect(() => monthSelect(field.value)), [selectedMonth]}/>
      )}
/>

如果这个解决方案不太好,请在评论中告诉我。我完全是初学者。