【问题标题】:React-Hook-Form Controller ignoring useEffectReact-Hook-Form 控制器忽略 useEffect
【发布时间】:2021-12-09 21:17:37
【问题描述】:

我有两个组件,其中 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]);

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

【问题讨论】:

  • 您能否更新 CodeSandbox,因为它现在不使用 RHF?至少没有使用&lt;Controller /&gt;。简而言之:有一种更简单的方法可以让您使用 useEffect (您也可以通过将其作为回调传递来错误地使用它),因为您可以在此处使用 RHF 的watch
  • 是的,它在 之前工作,不幸的是 它坏了,这就是为什么我认为提供坏沙盒没有意义。究竟是什么另一种方式,从几天开始,我就被困住了。但是,让我试试看,我是否可以先展示损坏的代码
  • codesandbox.io/s/jolly-brahmagupta-fdfkb - 请查看更改后的沙箱
  • 我玩了一会儿,问题是定义,控制器不允许重新渲染值。使用 useEffect 或 watch 正在监视这一年,因为我可以将每个更改记录到控制台。问题在于,setSelectedMonth 不会根据年份触发/不会渲染

标签: reactjs react-hook-form


【解决方案1】:

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

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

  • 当您使用 RHF 时,您无需为组件设置额外的状态,因为 RHF 将为您管理表单状态。
  • 如果您只使用一个日期作为整个出生日期会更简单 - 这样您将始终拥有年、月和日的当前值,而无需查看值或使用额外定义的状态

【讨论】:

  • 非常感谢您的努力,不幸的是它不会根据所选年份重新渲染月份。我得到的是一种年龄验证,基本上,我不能选择任何日期,这会使我的年龄小于 18 岁。所以,如果我选择 2002 年 12 月,然后切换到 2003 年,则需要重新选择 12 月渲染到十月(因为我们现在有十月)。选择任何可用日期都不会进行验证。有什么想法吗?
  • 我更新了我的 CodeSandbox 并删除了不需要的监视值。从用户体验的角度来看,向用户反馈提交日期必须早于至少 18 年,然后显示验证错误消息,这样用户就可以更正它。我在 CodeSandbox 中实现了这种行为。
  • 我认为 RHF 对您的用例来说完全是一个不错的选择,更不是好的 UI/UX 设计来神奇地更改字段值,因为这可能会使用户感到困惑。一个简单的错误消息肯定对用户更友好,因为很清楚当前选择的生日有什么问题。您对上一条评论和您描述的用例完全正确。我以某种方式删除了&lt;Controller /&gt; 的验证规则。我再次添加了它,所以现在它会显示错误消息,当用户应该执行上述技巧时。
  • 这是更新后的CodeSandbox 我认为现在应该不可能提交错误的生日。如果您真的需要通过自动更改其他字段来完成它 - 请告诉我,我将根据此要求更改 CodeSandbox。
  • 好的,最后一次尝试。 ? 我将其更改为您的要求 - 所以现在如果用户试图欺骗表单,它将跳回到可能的最年轻日期(今天 -18 岁)。我已经离开了表单验证,所以现在它应该非常安全。 ? 这是新的CodeSandbox
【解决方案2】:

答案太简单了,无法工作,但确实如此。有好几次我在这里How to change React-Hook-Form defaultValue with useEffect()? 阅读这篇文章,但无法真正理解,我在哪里以及如何使用 setValue。正如我假设的那样,我的选择值并没有改变,即使我正在观察兄弟状态的变化。

所以我将 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]}/>
      )}
/>

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

【讨论】:

    猜你喜欢
    • 2021-07-10
    • 2023-04-09
    • 2020-09-26
    • 1970-01-01
    • 2019-10-08
    • 2021-12-10
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多