question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Ordering of componentWillMount/Unmount in React 16

See original GitHub issue

Problem

It seems that the ordering of componentWillMount and componentWillUnmount is no longer guaranteed in React 16 due to support for async componentWillUnmount.

Previously, componentWillUnmount was always called on old components being removed before componentWillMount was called on new components.

Example

We have a Form component in which inputs “register” themselves with the parent Form in componentWillMount and deregister themselves in componentWillUnmount (this allows the Form to keep track of global state for all of the inputs). The following scenario will cause the Form to throw an error now that ordering is no longer guaranteed:

{ showTextInput ? <TextInput name="a" /> : <CheckboxInput name="a" /> }

In this scenario, it’s possible that the Form will try to register an input with the same name before the previous input has been unmounted, which is not allowed.

Question

While I understand the reasoning behind this change, I’m wondering what the suggested solution is if our code previously relied on componentWillUnmount firing before componentWillMount?

The most obvious solution that comes to mind is moving the registerInput step from willMount into didMount. However, this means we’ll have to deal with an unnecessary re-render upon mounting the input. Is this still the correct approach?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:5
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

7reactions
gaearoncommented, Feb 17, 2018

Let’s keep this open because the discussion is interesting and there may be some better ways to do it. Personally I don’t have much time to look into this now though.

6reactions
gaearoncommented, Aug 9, 2018

I think the conceptual issue in your examples is that this code only works correctly when there’s at most one <Input> with the same name prop in the tree at any given time. So if the “new” registration with the same name happens before the “old” registration is removed, the wrong one ends up being removed.

That tells me that the problem is with using the name as a registration key. What you really want is to register and unregister an individual input, not an individual name. One solution could be to generate a unique ID in each Input. When you register an input with the form, pass both its unique ID and name. Same when unregistering. Importantly, keep the data in the form component keyed by the ID rather than by name. This way, the order wouldn’t matter — even if fields with the same name exists at the same time, each input would read the correct data. And then when you actually need the name (e.g. for form submission) you could enforce that only one such field should exist (or ignore any but the first, for example).

But why do we even have this weird overlapping time when the new component “will mount” but the old one hasn’t unmounted yet? As I mentioned above it’s unavoidable to unlock future React features. But this is also the reason we don’t recommend using componentWillMount, and especially doing mutations there. It’s just like mutations in a constructor (which is also not recommended). So what’s the alternative? One thing you could do is to move the “registration” into componentDidMount (did). This way the order will be the one you expect. However, now the first render of a field would be before the data for it exists. One way to fix is it to teach the field itself to do something like let data = formFromContext[name] || myDefaultState. So on first render we wouldn’t have the data from parent yet, but we’d read our own default data. And during registration, we’d pass our default data upwards, thus “registering” it in the form’s state.

It seems to me like the second solution is more in line with how React works. Hope this helps.

Read more comments on GitHub >

github_iconTop Results From Across the Web

React.Component
componentWillUnmount () is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating ...
Read more >
What are the guarantees on React lifecycle event order ...
Here, x changing between true & false will unmount one component and mount the other. Are there guarantees about the order in which...
Read more >
React 16 Lifecycle Methods: How and When to Use Them
Since the lifecycle API is a bit more complex this time around, I've split the methods into four sections: mounting, updating, unmounting, and ......
Read more >
A beginners guide to the React component lifecycle
Our lifecycle is broadly categorized into three parts: Mounting, Updating and Unmounting. However, React 16 introduced a new method which, ...
Read more >
Understand the React Component Lifecycle Methods
[00:00] When our component is added to the DOM, this is called "mounting," and when our component is removed from the DOM, this...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found