简体   繁体   中英

'Can't perform a React state update on an unmounted component' ERROR when accessing the context api

I get the following error when I access the context api from my componentDidMount method. It is caused by refreshing the page, then the application crashes. If I'm navigating it normally I do not get an error.

react-dom.development.js?4646:506 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in Details (created by WithStyles(Details))
    in WithStyles(Details) (created by Context.Consumer)
    in Route (created by Apis)
    in Switch (created by Apis)
    in Apis (created by Context.Consumer)
    in Route (created by ProtectedApp)
    in Switch (created by ProtectedApp)
    in div (created by Layout)
    in div (created by Layout)
    in Layout (created by WithStyles(Layout))
    in WithStyles(Layout) (created by ProtectedApp)
    in MuiThemeProviderOld (created by ProtectedApp)
    in IntlProvider (created by ProtectedApp)
    in ProtectedApp (created by LoadableComponent)
    in LoadableComponent (created by Context.Consumer)
    in Route (created by Store)
    in Switch (created by Store)
    in Router (created by BrowserRouter)
    in BrowserRouter (created by Store)
    in Store
    in MuiThemeProviderOld

I found that it is caused by this line where I access the object returned from the context.

Any input on why this is happening and how can I fix this would be much appreciated.

The error seems to have been bubbling up from the Details/index.js:294 because the method updateActiveLink is invoked in render method.

I guess when you reload the page, this condition kicks in and tries to setState when the component is still rendering which is not the reason setState is designed for. setState will invoked render again unless the shouldComponentUpdate hook returns false which it does not in your case.

So, you can choose to change the way you handle setting the active link either in componentWillMount by setting it to a variable or by invoking it in componentDidUpdate and componentDidMount lifecycle hooks.

Another solution would be to return the calculated active state and use it accordingly

componentDidMount() {
  this.setState({active: this.getActiveLink()});
  ...
}

getActiveLink() {
    const { active } = this.state;
    const currentLink = this.props.location.pathname.match(/[^\/]+(?=\/$|$)/g);

    if (currentLink && currentLink.length > 0 && active !== currentLink[0]) {
        return currentLink[0];
    }

    return active;
}

render() {
  const active = this.getActiveLink();
  ...
}

Or a little more controversial fix would be to mutate in the method like below. IMHO state variable is just another, instance variable nothing fancy about it, as long as you are passing down the render cycle mutating state responsibly should not cause any side effects. Since it's almost as if you are doing operations on the state in the render method that too on a string variable active , it should not be a blatant error.

componentDidMount() {
  updateActiveLink(true);
  ...
}

updateActiveLink(setState) {
    const { active } = this.state;
    const currentLink = this.props.location.pathname.match(/[^\/]+(?=\/$|$)/g);

    if (currentLink && currentLink.length > 0 && active !== currentLink[0]) {
      if(setState) 
        this.setState({ active: currentLink[0] });
      else
        this.state.active = currentLink[0];
    }
}

render() {
  this.updateActiveLink(false);
  ...
}

NOTE: I am not encouraging state mutation or anything, I see it differently and use it differently as long as the render cycle obeys it's rules. Again this is one of my observations using setState in quite many complex components.

PS: Have not tried running the code, just a hunch / observation. Let me know if this works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM