final-form / react-final-form

🏁 High performance subscription-based form state management for React
https://final-form.org/react
MIT License
7.39k stars 481 forks source link

FormSpy.onChange callback unable to use closure over state reference #671

Open yourcelf opened 5 years ago

yourcelf commented 5 years ago

Are you submitting a bug report or a feature request?

Bug report

What is the current behavior?

In a functional component using useState hooks, callbacks passed to FormSpy.onChange which enclose state values only see the initial value of the state -- in other words, the onChange handler gets stale state values.

What is the expected behavior?

When passing a callback to FormSpy.onChange, it should behave like <input onChange={func} /> with respect to enclosed state values, and have access to the current value of enclosed vars.

Sandbox Link

https://codesandbox.io/s/react-final-form-loading-and-initializing-9h1gn

This example presents two input controls. The first one is a simple <input onChange={fetchTime} />, which fetches the current time when a character in the input box is changed.

The second input control is within a React Final Form Field. <FormSpy onChange={fetchTime} /> fetches the current time when the second input is changed.

The behavior of these two onChange handlers differs: the plain <input onChange={fetchTime} /> encloses the current value of the time state var. The FormSpy-based variant, however, does not; and only has access to the initial value of state.

What's your environment?

Other information

This behavior may be related to the specific way that the useFormState hook wraps the onChange call in useEffect. I can achieve similarly pathological behavior in the simple input.onChange handler if I define the handler with useCallback to prevent updates to the function:

const fetchTime = useCallback(() => {
    setWithinFetchTimeFunc(time);
    fetch("https://worldtimeapi.org/api/timezone/America/Denver")
    .then(res => res.json())
    .then(json => setTime(json.utc_datetime))
}, []);

this leads me to believe that the similar useEffect construct may be suppressing changes to the onChange function.

fzaninotto commented 5 years ago

Couldn't this be a duplicate of #569, which was solved by #572?

yourcelf commented 5 years ago

@fzaninotto I erred in my environment listing above: I'm seeing this behavior in react-final-form v6.3.0 which was after #572 landed. So while it may cover similar territory, I don't believe #572 fixed this.

yourcelf commented 5 years ago

Here's an updated code sandbox link which exhibits the behavior in:

https://codesandbox.io/s/react-final-form-loading-and-initializing-m2u9c

fzaninotto commented 5 years ago

The fix was not yet released. It is now in v6.3.1. I invite you to try again with the latest version.