React-router: Unsafe Lifecycle warning in React >= 16.3

Created on 3 Apr 2018  路  15Comments  路  Source: ReactTraining/react-router

Version

react-router@create-context-api
[email protected] under React.StrictMode

Steps to reproduce

use react-router under React.StrictMode

Expected Behavior

without warning

Actual Behavior

warning for componentWillReceiveProps componentWillMount

Most helpful comment

This is fixed in master. You can see some of my commits here and here.

You can expect a new beta release sometime this week! 馃槄

All 15 comments

For Router, we could write like this to fix the componentWillMount warning.
It works, but not sure is this a correct way.

https://github.com/ReactTraining/react-router/blob/react-context-api/packages/react-router/modules/Router.js#L79-L81

render() {
    const { children } = this.props;
    return (
      <RouterContext.Provider value={this.getChildContext()}>
        <HistoryListener history={this.props.history} onLocationChange={() => { this.setState(...) }} />
        {children ? React.Children.only(children) : null}
      </RouterContext.Provider>
    );
 }
class HistoryListener extends React.Component<{ history: History, onLocationChange: () => void }> {
  unlisten: any = null

  componentDidMount() {
    this.unlisten = this.props.history.listen(() => {
      this.props.onLocationChange()
    })
  }

  componentWillUnmount() {
    if (this.unlisten) {
      this.unlisten()
    }
  }

  render() {
    return null
  }
}

This should be fixed in v3 too.

@morlay No need to farm that out to another component. Instead, we can move to cDM and simply do a second check for if the location changed during that time.

Another option, if we wanted to go all-in on 16+, would be to use a setState callback function for the initial read from history.

Easy next step: Upgrade to React 16.3 locally and add a failing test, like I did here: reactjs/react-redux#918

@timdorr
In StrictMode,constructor static getDerivedStateFromProps and render will be double-invoked.

constructor -> static getDerivedStateFromProps -> render -> componentDidMount
There are no opportunity to do the second check. So i think to move history listener to another component.

Then we can have
Router#constructor -> Router.getDerivedStateFromProps -> Router#render -> HistoryListener#constructor -> HistoryListener#componentDidMount -> Others Components >Router#componentDidMount

logic in HistoryListener#componentDidMount will be same as old Router#componentWillMount.

I tried providing another callback method in context to omit location changes or proxy history push replace methods.
It only handle changes from children of Router and will miss others changes from history itself, like navigating by redux actions.

That's fine. We can add checks to avoid double execution.

Is there a PR to fix this?

I opened a PR, but I need someone to help me test this.

Created #6341 which hopefully is on the path of resolving this issue.

This is fixed in master. You can see some of my commits here and here.

You can expect a new beta release sometime this week! 馃槄

WOOOO!

@mjackson
There will be double listened under StrictMode, and the first listener will be an un-controlled callback and may cause some issue when history changed.
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Router.js#L42-L44

as I said https://github.com/ReactTraining/react-router/issues/6060#issuecomment-378432863

if we need to add listener in constructor, may try to unlisten before adding listener
js this.unlisten && this.unlisten() this.unlisten = .... ;

Yeah, that listen call should be in a cDM. It's going to leak in server rendering too.

Ah, good call @morlay. I'll fix in the next beta release.

@timdorr We can't use cDM because of the way <Redirect> works. But we can filter out the listen call based on whether we're in a persistent environment (the browser) or not.

@morlay @timdorr Let's follow up in #6363

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jzimmek picture jzimmek  路  3Comments

andrewpillar picture andrewpillar  路  3Comments

ArthurRougier picture ArthurRougier  路  3Comments

yormi picture yormi  路  3Comments

winkler1 picture winkler1  路  3Comments