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

DestroyOnUnregister incompatible with StrictMode in React18 #1031

Open ohlsen3000 opened 1 year ago

ohlsen3000 commented 1 year ago

Type of issue

Bug

What is the current behavior?

When opening a form with the attribute 'destroyOnUnregister' in StrictMode locally, the initial Values are not displayed.

What is the expected behavior?

When opening a form with the attribute 'destroyOnUnregister' in StrictMode locally, the initial Values are displayed.

Sandbox Link

See https://codesandbox.io/s/inspiring-cori-smyfhm?file=/src/App.js

What's your environment?

react-final-form: 6.5.9 final-form: 4.20.9 react: 18.2

Other information

As far as I can see, the values are rendered in the first cycle. Then StrictMode unmounts the fields, causing them to be removed from the form model (caused by 'destroyOnUnregister'). On the second mount, the initial values are considered to be identical, hence the fields will not be filled again but remain empty.

When running in production (i.e. w/o StrictMode) the form is filled. The form will also work correctly if:

gertdreyer commented 1 year ago

Strict Mode is a Breaking Change in React 18... It emulates unmounting and remounting the fields which would then obviously clear all the values from the formState.

There are workarounds out there e.g. https://blog.ag-grid.com/avoiding-react-18-double-mount/

Willing to accept a PR that fixes this behaviour.

Axnyff commented 1 year ago

Hi! I recently did a project on which we relied a lot on destroyOnUnregister and I'd be hard to implement the same feature with a FormSpy so I looked into your suggestion.

It's a bit complicated to try and handle correctly the behavior when you have dependencies or changing effect function ( the code in the link broke quite a lot of tests in final-form

I've managed to have a version that works here ( and for which the tests passes on react-final-form ) https://github.com/Axnyff/useEffectOnceInStrictMode/blob/main/useEffectOnceInStrictMode.ts with some tests here https://github.com/Axnyff/useEffectOnceInStrictMode/blob/main/useEffectOnceInStrictMode.test.js

I'm not sure I'm not missing some weird edge cases that would break the regular behavior of useEffect. It seems to fix the behavior of destroyOnUnregister if I only fix that useEffect: https://github.com/final-form/react-final-form/blob/main/src/useField.js#L113

It looks like it would be hard to bring the tests in react-final-form as they are only valid for react 18. Do you think there's a way I can do a PR to fix that behavior ?