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.