在render中调用setState是不可避免的

时间:2016-02-09 10:57:28

标签: asynchronous reactjs reactive-programming

React文档指出render函数应该 ,这意味着它不应该使用this.setState。但是,我相信当状态依赖于'remote'即来自ajax调用的结果。唯一的解决方案是setState()函数内的render

在我的情况下。我们的用户可以登录。登录后,我们还需要检查用户的访问权限(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内1}}违反React原则的函数

有更好的解决方案吗?提前致谢

1 个答案:

答案 0 :(得分:16)

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 />; } } }); 是一个大红旗;在这样一个简单的例子中它可以正常运行,但它是通向高度不可维护的组件的道路,而且它只能起作用,因为副作用是异步的。

相反,请考虑组件可以处于的各种状态 - 就像您在建模状态机一样(事实证明,您是):

  • 初始状态(用户未点击按钮)
  • 等待授权(用户点击登录,但我们还不知道Ajax请求的结果)
  • 用户可以访问某些内容(我们已收到Ajax请求的结果)

使用组件的状态对其进行建模,你就可以了。

<li><%# Eval("Alert") %></li>