React文档指出render函数应该是 纯 函数,这意味着它不应该在函数中使用this.setState。但是,我相信当状态依赖于“远程”(即由ajax调用产生的结果)时。唯一的解决方案是setState()在render函数内部
render
this.setState
setState()
就我而言。我们的用户应该可以登录。登录后,我们还需要检查用户的访问权限(ajax调用),以决定如何显示页面。代码是这样的
React.createClass({ render:function(){ if(this.state.user.login) { //do not call it twice if(this.state.callAjax) { var self=this $.ajax{ success:function(result) { if(result==a) {self.setState({callAjax:false,hasAccess:a})} if(result==b) {self.setState({callAjax:false,hasAccess:b})} } } } if(this.state.hasAccess==a) return <Page /> else if(this.state.hasAccess==a) return <AnotherPage /> else return <LoadingPage /> } else { return <div> <button onClick:{ function(){this.setState({user.login:true})} }> LOGIN </button> </div> } } })
之所以无法显示ajax调用,componentDidMount是因为当用户单击LOGIN按钮时,页面会重新呈现,并且还需要ajax调用。因此,我想唯一的位置setState就是render违反React原理的函数 内
componentDidMount
setState
有更好的解决方案吗?提前致谢
render应 始终 保持纯净。在那儿做副作用的东西是非常不好的做法,打电话setState是一个很大的危险信号。在这样的简单示例中,它可以解决问题,但是这是高度不可维护的组件之路,而且它只能起作用,因为副作用是异步的。
相反,请考虑您的组件可能处于的各种状态-就像您在建模状态机一样(事实证明,您是):
使用组件的状态对此建模,您很高兴。
React.createClass({ getInitialState: function() { return { busy: false, // waiting for the ajax request hasAccess: null, // what the user has access to /** * Our three states are modeled with this data: * * Pending: busy === true * Has Access: hasAccess !== null * Initial/Default: busy === false, hasAccess === null */ }; }, handleButtonClick: function() { if (this.state.busy) return; this.setState({ busy: true }); // we're waiting for ajax now this._checkAuthorization(); }, _checkAuthorization: function() { $.ajax({ // ..., success: this._handleAjaxResult }); }, _handleAjaxResult: function(result) { if(result === a) { this.setState({ hasAccess: a }) } else if(result ===b ) { this.setState({ hasAccess: b }) } }, render: function() { // handle each of our possible states if (this.state.busy) { // the pending state return <LoadingPage />; } else if (this.state.hasAccess) { // has access to something return this._getPage(this.state.hasAccess); } else { return <button onClick={this.handleButtonClick}>LOGIN</button>; } }, _getPage: function(access) { switch (access) { case a: return <Page />; case b: return <AnotherPage />; default: return <SomeDefaultPage />; } } });