final-form / final-form/react-final-form
useField causes useFormState#valid to temporarily be constantly true
- Dominant language
- JavaScript
- Stars
- 7.4k
- Forks
- 497
- PR merge metrics
- No merged PRs in 30d
Description
# the 'immediately unregister' behavior in `useField` triggers always `valid` status
### What is the current behavior?
In my form, every input does `useField` as expected. I also have a `FormError` component that displays `FORM_ERROR` and `submitError`s. It uses `useFormState()` to accomplish this as expected.
I also have a component/hook called `ValuesHandler` that allows me to easily get a callback whenever any of the values in the form changes (in my case, to sync this state to another component that wants to know the current state of the form, without coupling them further).
It looks a little something like
```jsx
/**
* ValuesHandler notifies callback function when form values change.
*/
export default function ValuesHandler({ onValues }) {
const form = useForm();
const { valid, validating, values } = useFormState({
subscription: {
valid: true,
validating: true,
values: true,
},
});
useEffect(() => {
if (!validating) {
onValues && onValues({ valid, values, form });
}
}, [form, onValues, valid, validating, values]);
return null;
}
```
Because of the mount order, what happens is:
- render a form and call `useForm`, triggering validation and then **pausing** validation
- register field A
- unregister field A, (clearing A's error and requesting record validation, but validation is paused)
- register field B
- unregister field B, (clearing B's error and requesting record validation, but validation is paused)
- call `useFormState` and immediately calculate the next form state, which has an empty errors object (since we unset every field's errors)
### What is the expected behavior?
the status of `useFieldState`'s `valid` property should not be dependent on the register/unregister calls made during component mounting. It should be
I hope my description was clear enough, not really sure how best to 'name' the bug.
### Sandbox Link
https://codesandbox.io/embed/intelligent-goodall-5kmg3
see the console for example. the `valid` property of `useFieldState` differs from that of the Form's render method, since validation is re-enabled before the second render
### What's your environment?
latest, all browsers
---
## Workaround
My workaround for now, which seems to be ok is to just add another condition to whether or not I notify my callbacks, whether or not the form is currently validating, and also use the properties from the render function instead of the actual subscriber state.
```js
import { useEffect } from 'react';
import { useForm } from 'react-final-form';
/**
* ValuesHandler notifies callback function when form values change.
*/
export default function ValuesHandler({ valid, validating, values, onValues }) {
const form = useForm();
useEffect(() => {
if (!validating && !form.isValidationPaused()) {
onValues && onValues({ valid, values });
}
}, [form, onValues, valid, validating, values]);
return null;
}
```
Contributor guide
Research direction
Start with the linked CodeSandbox and trace the mount order involving useField, useFormState, and paused validation. Compare the subscriber's valid state with the Form render output during the first render. Done means registration and unregistration during mounting no longer make valid temporarily report true.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100