Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
sandkampderek opened this issue Oct 25, 2017 · 19 comments · Fixed by #3956
Closed

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

sandkampderek opened this issue Oct 25, 2017 · 19 comments · Fixed by #3956
Labels
bug c:field-level-validation validation in field component

Comments

@sandkampderek
Copy link

sandkampderek commented Oct 25, 2017

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?

@marcneander
Copy link

Status on this?

@marcneander
Copy link

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

@Luchanso
Copy link

Luchanso commented Dec 1, 2017

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:

@Luchanso
Copy link

Luchanso commented Dec 4, 2017

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

@Guymestef
Copy link

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

@nicolai-shape
Copy link

Any news on this?

@SengitU
Copy link

SengitU commented Dec 20, 2017

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

@Elliot128
Copy link

Elliot128 commented Jan 16, 2018

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?

@SengitU
Copy link

SengitU commented Jan 16, 2018

@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.

@slavab89
Copy link

I believe that #3500 also relates to this

Betree added a commit to CaptainFact/captain-fact-frontend that referenced this issue Mar 5, 2018
viljark added a commit to viljark/redux-form that referenced this issue Mar 13, 2018
erikras pushed a commit that referenced this issue Mar 23, 2018
* Field not validating after re-mount (#3566)

* improve parameter name
@asaarnak
Copy link
Contributor

asaarnak commented Apr 2, 2018

@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?

@asaarnak
Copy link
Contributor

asaarnak commented Apr 2, 2018

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:

@wanaright10
Copy link

wanaright10 commented Apr 19, 2018

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()}

@erikras
Copy link
Member

erikras commented Jun 12, 2018

Fix released in v7.4.0.

@erikras erikras closed this as completed Jun 12, 2018
@asaarnak
Copy link
Contributor

asaarnak commented Jun 12, 2018

@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?

erikras pushed a commit that referenced this issue Jun 15, 2018
…#3566) (#3956)

* Use componentDidMount instead of componentWillMount to register Field, Fields, FieldArray. Fixes #3566

* Test field validate prop after unregister and register Field #3566

* PR improvement, remove duplicate code.

* PR improvement. lint, remove semicolons

* Use constructor instead of componentWillMount to register Field, Fields, FieldArray. PR comment: #3956 (comment)

* Revert "Use constructor instead of componentWillMount to register Field, Fields, FieldArray. PR comment: #3956 (comment)"

This reverts commit 82781c0
@kumarsaranya
Copy link

Hi,

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

@F-Adam-B
Copy link

F-Adam-B commented Apr 3, 2019

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

@sergeyromanovsky
Copy link

sergeyromanovsky commented Apr 24, 2019

This issue is still reproducable on redux-form 8.2

enableReinitialize : true solve the issue

@lock
Copy link

lock bot commented Apr 25, 2020

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.

@lock lock bot locked as resolved and limited conversation to collaborators Apr 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug c:field-level-validation validation in field component
Projects
None yet
Development

Successfully merging a pull request may close this issue.