简体   繁体   English

React:在设置状态之前初始渲染(通过ajax)

[英]React: initial render fires before state is set (via ajax)

I've set things up so the HomePage component renders UserShow for the current logged in user. 我已经进行了设置,因此HomePage组件为当前登录的用户呈现UserShow For example, if a user with an ID of 2 is logged in and visits the HomePage page, it will render their UserShow . 例如,如果ID为2的用户登录并访问HomePage页面,它将呈现其UserShow

The "normal" UserShow works correctly. “普通” UserShow正常工作。 For example if you type in /users/18, it will properly render. 例如,如果您键入/ users / 18,它将正确呈现。 However it's not working when HomePage renders it. 但是,当HomePage呈现它时,它无法正常工作。

I'm new to React (especially its lifecycle methods), so my debugging has been to throw alerts in at various steps. 我是React的新手(特别是它的生命周期方法),所以我的调试是在各个步骤中发出警报。 I'd say the most important findings to share are: 我要说的最重要的发现是:

  1. currentUserID( ) is functioning and returns the correct ID currentUserID()正在运行并返回正确的ID
  2. Hard-coding the value of state.userID within componentDidMount causes things to work correctly componentDidMount中state.userID的值进行硬编码会使事情正常工作

These two points lead me to believe that Render is being called before it can update state.userID with its (correct) return value. 这两点让我相信Render在被更新state.userID及其(正确的)返回值之前被调用。 Even more specific is that it's rendering before the .success portion of the this.currentUserID() ajax call returns. 更具体的是它在this.currentUserID() ajax调用返回的.success部分之前呈现。 If this is so, what's the best way to go about not doing an initial render until an ajax call like this completes? 如果是这样,那么在这样的ajax调用完成之前,最好的方法是不进行初始渲染?

My code is in a state of spaghetti - it's my first time doing front-end routing with JavaScript. 我的代码处于意大利面状态 - 这是我第一次使用JavaScript进行前端路由。 I'm also managing sessions via using the user's email as the token in localStorage - I'm new to sessions in JS as well. 我也通过使用用户的电子邮件作为localStorage中的令牌管理会话 - 我也是JS中的新会话。 Please bear with me. 请多多包涵。

HomePage component: 主页组件:

var HomePage = React.createClass({

getInitialState: function(){
    return{
        didFetchData: false,
        userID: null,
    }
},

componentWillMount: function(){
    newState = this.currentUserID()
    this.setState({userID: newState}) 
    // this.setState({userID: 2})   //hard-coding the value works
},

currentUserID: function(){
    if(App.checkLoggedIn()){
        var email = this.currentUserEmail()
        this.fetchUserID(email)
    }else{
        alert('theres not a logged in user')
    }
},

currentUserEmail: function(){
    return localStorage.getItem('email')
},

fetchUserID: function(email){ //queries a Rails DB using the user's email to return their ID
    $.ajax({
        type: "GET",
        url: "/users/email",
        data: {email: email},
        dataType: 'json',
        success: function(data){
            this.setState({didFetchData: 'true', userID: data.user_id})
        }.bind(this),
        error: function(data){
            alert('error! couldnt fetch user id')
        }
    })
},

render: function(){
    userID = this.state.userID
    return(
        <div>
            <UserShow params={{id: userID}} />
        </div>
    )
}
})

UserShow component: UserShow组件:

var UserShow = React.createClass({

getInitialState: function(){
    return{
        didFetchData: false,
        userName: [],
        userItems: [],
        headerImage: "../users.png"
    }
},

componentDidMount: function(){
    this.fetchData()
},

fetchData: function(){  
    var params = this.props.params.id
    $.ajax({
        type: "GET",
        url: "/users/" + params,
        data: "data",
        dataType: 'json',
        success: function(data){
            this.setState({didFetchData: 'true', userName: data.user_name, userItems: data.items, headerImage: data.photo_url})
        }.bind(this),
        error: function(data){
            alert('error! couldnt load user into user show')
        }
    })
},

render: function(){
    var userItem = this.state.userItems.map(function(item){
        return <UserItemCard name={item.name} key={item.id} id={item.id} description={item.description} photo_url={item.photo_url} />
    })
    return(
        <div>
            <Header img_src={this.state.headerImage} />

            <section className="body-wrapper">
                {userItem}              
            </section>
        </div>
    )
}
})

So what you want to do is to avoid rendering anything until your ajax-request returns your result. 所以你想要做的是避免渲染任何东西,直到你的ajax请求返回你的结果。

You can do a check in the render method if the state is how you want it. 如果状态是您想要的状态,您可以检查渲染方法。 If it's not, then return null, or a loader or some other markup. 如果不是,则返回null,或者加载器或其他标记。 When the componentDidMount then sets the state, it will trigger a re-render, since the userID then is set, it will return the userShow component 当componentDidMount然后设置状态时,它将触发重新渲染,因为然后设置了userID,它将返回userShow组件

Example: 例:

render(){
  if(this.state.userID === null){
     return null; //Or some other replacement component or markup
  }

  return (
    <div>
        <UserShow params={{id: userID}} />
    </div>
  );

}

Fetching the data in the userShow component could be done like this: 获取userShow组件中的数据可以这样完成:

componentWillReceiveProps(nextProps){
    //fetch data her, you'll find your prop params in nextProps.params
}

You can also avoid doing this here, by kicking the data-fetch in the render-method. 你也可以通过在render-method中踢数据获取来避免这样做。

Your initial data set what your doing in componentWillMount will not help to set data because you want to fetch data from ajax. 您的初始数据集在componentWillMount中执行的操作无助于设置数据,因为您想从ajax获取数据。 Debug fetchUserID and currentUserID function whether your getting correct email from localstorage and user id from server. 调试fetchUserID和currentUserID函数是否从localstorage获取正确的电子邮件,从服务器获取用户ID。 Others is fine. 其他人很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM