redux-form/redux-form

Re-mounting a Field component erases the field-level validation function

Closed this issue ยท 19 comments

Are you submitting a bug report or a feature request?

Bug report

What is the current behavior?

When a Field with a field-level validation function attached to it is unmounted and immediately re-mounted, that validation function will never be run again.

In the example below, when the key changes, the Field will be unmounted and re-mounted, and the validation function will never be run again:

      <Field
        key={`${this.state.firstNameFieldKey}`}
        component={renderField}
        name="firstName"
        validate={this.validateFirstNameField}
      />

Perhaps a more common method of unmounting and remounting fields is conditional rendering of fields with the same name. In the example below, when this.state.shouldRenderTextArea changes, the validate function will never be run again:

const FirstNameTextArea = () => (
    <Field
      name="firstName"
      component={renderTextArea}
      validate={validateFirstNameField}
    />
);

const FirstNameTextField = () => (
    <Field
      name="firstName"
      component={renderTextField}
      validate={validateFirstNameField}
    />
);

/*In the form's render method: */
{
  this.state.shouldRenderTextArea ?
    <FirstNameTextArea />
    :
    <FirstNameTextField />
}

What is the expected behavior?

After the field is re-mounted, its validation function should run.

Sandbox Link

https://codesandbox.io/s/m7l1lyzyoy

What's your environment?

redux-form 7.1.1
react 16.0.0

Other information

The problem appears to be that Field registers the validate function in componentWillMount, and erases the validate function in componentWillUnmount. However, React 16 will always run componentWillMount of the new component BEFORE componentWillUnmount of the old component. That means that we register the new validate function, and immediately delete it.

Would there be any problem with having Field register itself it componentDidMount instead?

Status on this?

To add some context: I get the same problem on all 7.x.x versions. Works as expected on 6.8.0

React: 15.6.2

Yes, I have the same problem. It was because componentWillUnmount call after componentWillMount.

-> componentWillMount First
--- Start Remounting
-> componentWillMount Second
-> componentWillUnmount First

I think redux-form must call register function when componentDidMount. I can try make PR for this? But I don't know what's can broke if register function will move in componentDidMount...

related links:

I solve this problem via destroyOnUnmount: false, but I don't know what's wrong if you use it in your own project.

I used destroyOnUnmount: false too as a temporary workaround, but a side-effect is that the form keep the submitted values as initialValues...

Any news on this?

Hi folks, I also have this issue. Thanks to @Luchanso , I am using workaround. Do you have any news on this issue?

I can't use the destroyOnUnmount workaround because we need to destroy other form values on unmount. Is there any way to target this prop against a single field on the form?

@Elliot128 we also had same issue. We first thought about clearing values by firing change action, but this approach will keep the validation errors. So we decided to register/deregister fields manually, until we find a good solution.

I believe that #3500 also relates to this

@erikras @gustavohenke
I tested that the referenced @viljark PR #3909 merge helps, but doesn't fix this issue.

I think @sandkampderek suggestion to use componentDidMount to register Field is correct. Because React 16 calls componentDidUnmount after componentWillMount and the new Field is unregistered immediately.

I tested registering Field in componentDidMount instead of componentWillMount and the Field validation was fixed.

Reactjs docs say that we should avoid componentWillMount and use componentDidMount for any side-effects or subscriptions. In react 17 componentWillMount is scheduled to be deleted.
https://reactjs.org/docs/react-component.html#unsafe_componentwillmount
"Avoid introducing any side-effects or subscriptions in this method. For those use cases, use componentDidMount() instead."

@erikras @gustavohenke
What do you think would it be possible to register Field in componentDidMount instead of componentWillMount to fix this issue?

Seems that we should use componentDidMount
When using React strict mode:

<React.StrictMode>
 <App/>
</React.StrictMode>

Then error is printed to console:
componentWillMount: Please update the following components to use componentDidMount instead:

I met this issue as well, but I found a intreating solution:

not working below:
const ConditionalComponent = () => someCondition? <ReduxFormFieldComponentOne /> : <ReduxFormFieldComponentTwo />;

render() {
<ConditionalComponent />
}

working below:
const ConditionalComponent = () => someCondition? <ReduxFormFieldComponentOne /> : <ReduxFormFieldComponentTwo />;

render() {
{ConditionalComponent()}
}

Someone can explain this? The only diff is one use < />, another one use {func()}

Fix released in v7.4.0.

@erikras
As redux-form still uses unsafeComponentWillMount. See https://github.com/erikras/redux-form/blob/master/src/createField.js#L41
I think this isn't fixed.
This issue initial comment. See: #3566 (comment)

The problem appears to be that Field registers the validate function in componentWillMount, and erases the validate function in componentWillUnmount. However, React 16 will always run componentWillMount of the new component BEFORE componentWillUnmount of the old component. That means that we register the new validate function, and immediately delete it.

Would there be any problem with having Field register itself it componentDidMount instead?

Hi,

is this issue resolved? I am facing similar issue and still need to depend on onDestroyUnmount: false workaround.

Hi,
Having a similar issue here. Using version 7.4.2 with React 16.6.0 when setting field level validation it not only doesn't error, the entire field disappears if I don't input a value and I then tab through to the next field. onDestroyUnmount isn't helping either.

thanks for any help to resolve these issues

This issue is still reproducable on redux-form 8.2

enableReinitialize : true solve the issue

lock commented

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.