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

Removing last item from array doesn't make the form dirty #395

Open ghost opened 5 years ago

ghost commented 5 years ago

What is the current behavior?

When I have an array of items, removing the last item doesn't make the form dirty. Therefor, if you use pristine to enable/disable the form submission button, it won't become enabled.

This was not the case in an older version (I'm not sure if the bug is in final-form, final-form-arrays, react-final-form or react-final-form-arrays).

Steps to reproduce

  1. Use the first CodeSandbox link
  2. Hit the X mark at the last item
  3. The Submit button doesn't become enabled, because the form is not dirty (pristine).

You can see that pristine on the bottom is true, which should be false,

What is the expected behavior?

Removing the last item in an array will make the form dirty (pristine should become false). Use the second CodeSandbox as a reference.

Sandbox Link

Unexpected behavior: https://codesandbox.io/s/14nqx1w807 Expected behavior: https://codesandbox.io/s/5m284838xn

What's your environment?

OS: Windows 10 1809 Browsers: Mozilla Firefox 63.0.3 and Google Chrome 71.0.3578.80.

Versions where it works as expected:

final-form: 1.2.1 final-form-arrays: 1.0.0 react: 16.2.0 react-dom: 16.2.0 react-final-form: 1.1.1 react-final-form-arrays: 1.0.0

Versions where it does not work as expected:

final-form: 4.10.0 final-form-arrays: 1.1.0 react: 16.4.2 react-dom: 16.6.2 react-final-form: 3.6.7 react-final-form-arrays: 1.1.0

Other information

As you can see, in the first CodeSandbox the Submit button becomes enabled (and you can also see that the pristine value is false), and in the second CodeSandbox, the Submit button doesn't become enabled (and you can also see that the pristine value is true).

You can see that the Submit button becomes enabled for a very short time and then it becomes disabled. In the first render, pristine is actually false, but in the second render, pristine becomes true, which disables the button.

carlreid commented 5 years ago

If you run into this issue, you could look into implementing the isEqual function on FieldArrayProps. For example:

<FieldArray
   name="customers"
   isEqual={(a: any, b: any) => {
            if (a && b) {
              if (a.length !== b.length) {
                return false;
              }
              for (let i = 0; i < a.length; i++) {
                if (a[i] !== b[i]) {
                  return false;
                }
              }
              return true;
            }
            return false;
    }}
...
/>

You will need a least version react-final-form-arrays@2.0.0 which also requires react-final-form@4.0.0

For anyone that doesn't need typings, you can minimise your upgrades to only react-final-form-arrays@1.1.0.

ghost commented 5 years ago

@carl-coolblue I can confirm that this workaround works. Thanks!