3
votes

I am fetching data in componentDidMount and updating the state and the famous warning is appearing:

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.

state = {
    post: null
}

render() {
    console.log(this.props.postId)
    if (this.props.post) {
        return (
            <div>
                <h3> {this.state.post.postTitle} </h3>
                <p> {this.state.post.postBody} </p>
            </div>

        );
    } else {
        return <Redirect to="/blog" />
    }
}
componentDidMount() {
    this._isMounted = true;
    axios
        .get('https://jsonplaceholder.typicode.com/posts/' + + this.props.postId)
        .then((response) => {
            let post = {
                id: response.data.id,
                postTitle: response.data.title,
                postBody: response.data.body
            }
            this.setState((prevState,props)=>{
                console.log('post',post)
                console.log('prevState',prevState)
                console.log('props',props)
            })
        })
        .catch((e) => {
            console.log('error', e)
        })
}

}

What is causing this warning and what is the best way to fetch the data and update the state?

2
The component may get unmounted again before the Ajax request via axios completes.Felix Kling

2 Answers

4
votes

Your question is the same as the following question.

How the component is developed, you can enter a loop and execute the render infinitely. To prevent it, add one more state and control to make the request only 1 time or those that need but that are "mindful".

Also, your code needs some changes, you can use the State to validate whether to show something or not and once the request is made, set the state again. With some change your code can look like this:

state = {
    loadingData: true,
    post: null
}

render() {
    if (!this.state.loadingData) {
        return (
            <div>
                <h3> {this.state.post.postTitle} </h3>
                <p> {this.state.post.postBody} </p>
            </div>
        );
    } else {
        return <Redirect to="/blog" />
    }
}
componentDidMount() {
    this._isMounted = true;
    if(this.state.loadingData)
        axios
            .get('https://jsonplaceholder.typicode.com/posts/' + + this.props.postId)
            .then((response) => {
                this.setState({
                    loadingData: false,
                    post: {
                        id: response.data.id,
                        postTitle: response.data.title,
                        postBody: response.data.body
                    }
                })
        })
        .catch((e) => {
            console.log('error', e)
        })
}

I hope it's useful. Regards

1
votes

Just create flag in state: isMounted: false. In componentDidMount set state isMounted = true and in componentWillUnmount: set state isMounted = false.

And in the async function that need use setState function, wrap them by condition if(this.state.isMounted) { ....setState action }