react-hook-form: Rules of Controller does not react to changes

First, the lib is very cool!! Thanks!

My problem is in set the rule in Controller:

{{ required: needRegister, min: 3 }}

The property rules of Controller does not not react to needRegister

Codesandbox link (Required)

Expected behavior React to changes in rules

Desktop (please complete the following information):

  • OS: Arch Linux Amd64
  • Browser Firefox
  • Version 77

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 36 (24 by maintainers)

Most upvoted comments

@bluebill1049 Controlled Input and Uncntrolled Input are inconsistent. Shouldn’t this be fixed?

https://codesandbox.io/s/react-hook-form-controller-template-oolpt

if anyone’s situation is simply depend on a prop, and it change only once, maybe use key prop to force Controller recreate the component helps

<Controller
  name='number'
  control={control}
  as={InputNumber}
  defaultValue={1}
  // @see https://github.com/react-hook-form/react-hook-form/issues/1749
  key={promotion ? 'YES' : 'NO'}
  rules={{
    required: '必填',
    min: {
      value: 1,
      message: '不能小于1',
    },
    validate: (value: number) => {
      if (!hasAttended && promotion) {
        const valid = value <= promotion.joinMax

Thanks for your feedback. have a read on the note above first to understand the rationale behind: https://github.com/react-hook-form/react-hook-form/issues/1749#issuecomment-637248515

I have to do some explanations why I have add a useEffect here, bacause it looks werid in the > “business logic” code. (I event dont really understand why unregister it can make it work, because unregister trigger something in RHF so it re-registered again ?)

Because rules are cached, so once it’s unregistred, it will get registered at the render with updated rules.

and another common case is, form validation, offen need some “context” information, that I have to fetch something customer specific details to determin final rules, so make rules react to the props or something similar feel more proper to me

if it’s coming down as props, then same use case with unregister, if it’s trigger by user input, you can use validate and getValues.

Screen Shot 2020-06-02 at 3 00 13 pm

Sorry deleted previous message…

I think i found an easier solution: you can update the rules by invoking register again.

https://codesandbox.io/s/controller-rules-8pd7z?file=/src/App.tsx

let me know if this helps.

Summarise

We have the following options:

  1. register on each render without cache rules
  • con: perf and why you do not change rules, it’s an overkill
  • prop: work when you change rules
  1. let users cache their own rules
const rules1 = useMemo(() => rules, [....]])
const rules2 = useMemo(() => rules, [....]])
<Controller rules={rule1} />
<Controller rules={rule2} />
  • con: not great DX
  • prop: works and good perf
  1. cache the rules
  • con: update rules are not great DX
  • prop: perf and have work-around

3 ✅(what we choose at the moment, cheap and have work-around)

@bluebill1049 I think should be fix the line below. we should custom compare deps (rulesRef).

https://github.com/react-hook-form/react-hook-form/blob/v5.7.2/src/controller.tsx#L110

yea, hopefully not going to introduce too much code for this change. I did have a note on the documentation on this too that we cache the rules.

We do have compareObject method, but then you will need deep compare with validating function which is not going to be pretty and light weight compare.

Ops! Validate do not work with values of useState, and defaultValues() dot not set values of getValues() 😕 Does the development version already support this?

This is exactly my issue as well. Values of useState are not respected by Validate. Will this be what is addressed in v6 @bluebill1049?

Yes, correct. right now you have to follow what i did above for a work around.

This? Okay, thanks @bluebill1049 ! I have the luxury of waiting for the release, so I’ll do that for now!

@acfasj we are fixing this next release.

Cant build a component that includes all of these fields because they are already in different bigger components inside my project.

I’ve already tried that approach and coudnt make it work, bu ill try again. Using controller and setValue together as work as expected for the entire form, except for this little problem.

ok, I will take a look closer during lunch time.

Thanks 😄

#1749 (comment)

You’re right. This may not be light weight compare.

I think we should take this as a tradeoff and documented the solution and attach that under the rules section.

  • external state: leverageunregister.
  • local input state: use validate function with getValues() to read other inputs’ value .

🤔 an alternative solution will be on users to memo all the rules, which is not great DX.

const rules1 = useMemo(() => rules, [....]])
const rules2 = useMemo(() => rules, [....]])

<Controller rules={rule1} />
<Controller rules={rule2} />

we cache the rules object inside the controller, hence the validation rules is not changing. (so the user doesn’t have to memo the rules object themself)

Solutions

  • use validate function combined getValues() (assume the toggle input is register with hook form as well)
  • unregister that input, so input gets re-registered with updated rules.