Set ReactJS state asynchronously

一世执手 提交于 2021-01-27 03:53:10

问题


If you do an asynchronous action that updates the state in componentWillMount (like the docs say), but the component is unmounted (the user navigates away) before that async call is complete, you end up with the async callback trying to set the state on a now unmounted component, and an

"Invariant Violation: replaceState(...): Can only update a mounted or mounting component."

error.

What's the best way around this?

Thanks.


回答1:


update 2016

Don't start using isMounted because it will be removed from React, see the docs.

Probably the best solution for problems arising from async call from cmomponentWillMount is to move things to componentDidMount.

More info about how to properly get around this problem and how not to need to use isMounted here: isMounted is an Antipattern




回答2:


You can use component.isMounted method to check if component was actually attached to the DOM before replacing its state. Docs.

isMounted() returns true if the component is rendered into the DOM, false otherwise. You can use this method to guard asynchronous calls to setState() or forceUpdate().

UPD: Before you downvote. This answer was given 2 freaking years ago. And it was the way to do stuff back that days. If you are just starting to use React do not follow this answer. Use componentDidMount or whatever another lifecycle hook you need.




回答3:


isMounted() is actually an easy way to solve most problems, however, I don't think this is an ideal solution for concurrency issues.

Now imagine that the user clicks very fastly on many buttons, or maybe he has a very poor mobile connection. It may happen that finally 2 concurrent requests are pending, and on completion will update the state.

If you fire request 1 and then request 2, then you would expect the result of request 2 to be added to your state.

Now imagine for some reason request 2 ends up before request 1, this will probably make your app unconsistent because it will show request2 results and then request 1, while your last "interest" was actually in request 1 answer.

To solve this kind of issue, you should rather use some kind of Compare And Swap algorithm. Basically, this means before issuing the request, you put some object node in state, and on request completion, you compare with reference equality if the node to swap is still be node you are interested in when the request completes.

Something like this:

var self = this;
var resultNode = {};
this.setState({result: resultNode});
this.getResult().then(function(someResult) {
    if ( self.state.result === resultNode ) {
        self.setState({result: someResult})
    }
}):

With something like that, you will not have concurrency issue in case the user clicks to fast on the buttons leading to current requests inside the same component.



来源:https://stackoverflow.com/questions/25067364/set-reactjs-state-asynchronously

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!