React – 在挂载的组件上设置setState()

在我的反应组件im试图实现一个简单的微调,而ajax请求正在进行 – 即时通讯使用状态来存储加载状态。

出于某种原因,下面这段代码在我的React组件中会引发这个错误

只能更新已安装或已安装的组件。 这通常意味着您在卸载的组件上调用了setState()。 这是一个没有操作。 请检查未定义组件的代码。

如果我摆脱了第一个setState调用错误消失。

constructor(props) { super(props); this.loadSearches = this.loadSearches.bind(this); this.state = { loading: false } } loadSearches() { this.setState({ loading: true, searches: [] }); console.log('Loading Searches..'); $.ajax({ url: this.props.source + '?projectId=' + this.props.projectId, dataType: 'json', crossDomain: true, success: function(data) { this.setState({ loading: false }); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString()); this.setState({ loading: false }); }.bind(this) }); } componentDidMount() { setInterval(this.loadSearches, this.props.pollInterval); } render() { let searches = this.state.searches || []; return (<div> <Table striped bordered condensed hover> <thead> <tr> <th>Name</th> <th>Submit Date</th> <th>Dataset &amp; Datatype</th> <th>Results</th> <th>Last Downloaded</th> </tr> </thead> { searches.map(function(search) { let createdDate = moment(search.createdDate, 'X').format("YYYY-MM-DD"); let downloadedDate = moment(search.downloadedDate, 'X').format("YYYY-MM-DD"); let records = 0; let status = search.status ? search.status.toLowerCase() : '' return ( <tbody key={search.id}> <tr> <td>{search.name}</td> <td>{createdDate}</td> <td>{search.dataset}</td> <td>{records}</td> <td>{downloadedDate}</td> </tr> </tbody> ); } </Table > </div> ); } 

问题是为什么我得到这个错误,当组件已经被挂载(因为它是从componentDidMount调用)我认为这是安全的组件状态一旦设置状态?

没有看到渲染function有点困难。 虽然已经可以find你应该做的事情,但每次使用间隔时,你都必须在卸载时清除它。 所以:

 componentDidMount() { this.loadInterval = setInterval(this.loadSearches, this.props.pollInterval); } componentWillUnmount () { this.loadInterval && clearInterval(this.loadInterval); this.loadInterval = false; } 

由于这些成功和错误callback在unmount之后仍然可能被调用,所以可以使用intervalvariables来检查它是否被挂载。

 this.loadInterval && this.setState({ loading: false }); 

希望这有助于提供渲染function,如果这不做的工作。

干杯

问题是为什么我得到这个错误,当组件已经被挂载(因为它是从componentDidMount调用)我认为这是安全的组件状态一旦设置状态?

不是componentDidMount调用的。 你的componentDidMount产生一个callback函数,它将在定时器处理程序的堆栈中执行,而不是在componentDidMount堆栈中执行。 显然,在你的callback( this.loadSearches )被执行的时候,组件已经卸载了。

所以接受的答案会保护你。 如果您正在使用其他一些不允许取消asynchronousfunction的asynchronousAPI(已经提交给某个处理程序),则可以执行以下操作:

 if (this.isMounted()) this.setState(... 

这将摆脱所有情况下报告的错误消息,尽pipe它确实感觉像在地毯下扫描东西,特别是如果您的API提供取消function(如setIntervalclearInterval )。

其实根据Facebook isMounted是一个反模式。 谁需要一个快速的解决scheme,ref属性的callback方法可以是一个解决方法。 handleRef的参数是对div DOM元素的引用。

有关参考和DOM的详细信息: https : //facebook.github.io/react/docs/refs-and-the-dom.html

 handleRef = (divElement) => { if(divElement){ //set state here } } render(){ return ( <div ref={this.handleRef}> </div> ) } 

对于后人来说,

在我们的例子中,这个错误与Reflux,callback,redirect和setState有关。 我们发送了一个setState给onDonecallback函数,但是我们也发送了一个redirect到onSuccesscallback函数。 在成功的情况下, 我们的onSuccesscallback会在onDone之前执行 。 这会在尝试的setState之前导致redirect 。 因此,一个未安装的组件的错误,setState。

回stream店行动:

 generateWorkflow: function( workflowTemplate, trackingNumber, done, onSuccess, onFail) {... 

修复之前调用:

 Actions.generateWorkflow( values.workflowTemplate, values.number, this.setLoading.bind(this, false), this.successRedirect ); 

修复后调用:

 Actions.generateWorkflow( values.workflowTemplate, values.number, null, this.successRedirect, this.setLoading.bind(this, false) ); 

更多

在某些情况下,由于React的isMounted是“已弃用/反模式”,我们已经采用_mountedvariables并自己监控它。