final-form / final-form/react-final-form
Bug: useFormState implementation may swallow state updates
- Dominant language
- JavaScript
- Stars
- 7.4k
- Forks
- 497
- PR merge metrics
- No merged PRs in 30d
Description
### Are you submitting a **bug report** or a **feature request**?
bug report
### What is the current behavior?
Current implementation of `useFormState` hook is not reliable. State initialization and `useEffect` hook are called asynchronously:
https://github.com/final-form/react-final-form/blob/abd6d6266d2f6953a1995cb3dedd26f198e653fc/src/useFormState.js#L19-L46
This means, that between this two calls, the form state may be changed. And yes, it happens sometimes :(
### What is the expected behavior?
When you using `useFormState` hook it should replicate **all** calls of `form.subscribe()`'s callback!
I think, that `firstRender.current` is a bad way for skipping needless state updates. Because this may cause skipping of really important updates from subscription. Instead I suggest the following implementation:
```js
function useFormState({
onChange,
subscription = all,
}: UseFormStateParams = {}): FormState {
const form: FormApi = useForm('useFormState');
const unsubscribe = React.useRef(() => {});
// synchronously register and unregister to query field state for our subscription on first render
const [state, setState] = React.useState>(
(): FormState => {
let initialState: FormState;
let initialRender = true;
unsubscribe.current = form.subscribe((state) => {
if (initialRender) {
initialState = state;
initialRender = false;
} else {
setState(state);
}
if (onChange) {
onChange(state);
}
}, subscription);
return initialState;
},
);
React.useEffect(
() => unsubscribe.current,
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
return state;
}
```
### Sandbox Link
Contributor guide
Assessment
This issue has not been assessed yet.