Reputation: 11329
I'm currently using React 16.3(React Native), written here, it suggests that I SHOULD be making any async requests inside of componentDidMount instead of componentWillMount because that will soon be deprecated.
Unfortunately I'm getting a no-op warning as I'm trying to fetch data inside of componentDidMount, setting the data returned from my axios request as my state.
Here's a snippet —
export default class MyComponent extends Component {
state = {
myData: []
}
componentDidMount() {
axios.get('api-endpoint')
.then(res => this.setState({ myData: res.data })
}
render() { return <View>...</View> }
}
and the warning —
Warning: Can only update a mounted or mounting component.
This usually means you called setState, replaceState, or
forceUpdate on an unmounted component. This is a no-op.
Please check the code for the MyComponent component.
Upvotes: 2
Views: 2842
Reputation: 11329
Update — The reason why my component was getting unmounted because I was setting state in my parent component. When setting state in the parent component, it forced a re-rendering of the component, which trickled down the tree & dismounted in the middle of my asynchronous request.
Upvotes: 1
Reputation: 428
My suggestion would be to follow proper Flux. You can attach a store listener for your MyComponent
in componentDidMount()
as follows.
componentDidMount() {
//call async data fecthing method here
store.addListener('eventname', onDataReceipt);
}
Before this, you can move the state change logic to onDataReceipt
method. Call the async Data fetch from componentDidMount()
and dispatch
an action for which a store has registered to. Then emit the event from store. Since you have already subscribed to the event in componentDidMount()
, on event emission onDataReceipt()
would be executed.
Also dont forget to remove the listener in componentWillUnMout()
componentWillUnMount() {
store.removeListener('eventname', onDataReceipt);
}
Flux would take care of the rest And you wouldn' thave to worry about the warning.
Upvotes: 1
Reputation: 36179
That's the problem of having asynchronous code in your components. When for example Promise resolves (might take few seconds), a user may have already navigated to another part of your application, so when Promise resolves and tries to execute setState
- you get the error that you try to update unmounted component.
My suggestion is to use something like redux-thunk, redux-saga or redux-observable etc. for your asynchronous logic... However, you can do a simple check - but it is an antipattern :
export default class MyComponent extends Component {
state = {
myData: []
}
componentDidMount() {
this.isMounted = true;
axios.get('api-endpoint')
.then(res => {
if(this.isMounted) {
this.setState({ myData: res.data })
}
})
}
componentWillUnmount() {
this.isMounted = false;
}
render() { return <div>...</div> }
}
Upvotes: 4