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

TCannadySF

I've set things up so the HomePage component renders UserShow for the current logged in user. For example, if a user with an ID of 2 is logged in and visits the HomePage page, it will render their UserShow.

The "normal" UserShow works correctly. For example if you type in /users/18, it will properly render. However it's not working when HomePage renders it.

I'm new to React (especially its lifecycle methods), so my debugging has been to throw alerts in at various steps. I'd say the most important findings to share are:

  1. currentUserID( ) is functioning and returns the correct ID
  2. Hard-coding the value of state.userID within componentDidMount causes things to work correctly

These two points lead me to believe that Render is being called before it can update state.userID with its (correct) return value. Even more specific is that it's rendering before the .success portion of the this.currentUserID() ajax call returns. If this is so, what's the best way to go about not doing an initial render until an ajax call like this completes?

My code is in a state of spaghetti - it's my first time doing front-end routing with 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. 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:

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>
    )
}
})
thsorens

So what you want to do is to avoid rendering anything until your ajax-request returns your result.

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. 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

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:

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.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

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

From Dev

React parent renders with initial state before successful ajax call sets state

From Dev

React - Load Initial List via AJAX

From Dev

how to set state in render react native

From Java

React onClick function fires on render

From Dev

Axios AJAX call in React returning only initial state

From Dev

How can I set initial React state from API data?

From Dev

react native - getting state from storage on before render()

From Dev

Set ajax-fetched data to component before render

From Dev

Alert invoked in React JS componentDidMount lifecycle method pops up before the initial render instead of after

From Java

Load state/data before render?

From Java

Reset to Initial State with React Hooks

From Dev

React initial state. counting

From Java

React hooks - set state of Parent from child via function

From Dev

Is there a way of capturing element state before MutationObserver mechanism fires (onVisibilityChanged)?

From Java

Make React useEffect hook not run on initial render

From Dev

React.js: Refs are not available on initial render

From Dev

React CSS animations only after initial render

From Dev

how to set initial value in react?

From Dev

how to set initial value in react?

From Dev

Set initial state for missing key in component data

From Dev

Set initial state with multiple async calls in Redux

From Dev

Set initial state on RadioGroup without entering OnCheckedChangeListener

From Dev

Set initial background color before loading

From Dev

Set $rootScope before textAngular directive initial

From Dev

React/Redux server side rendering initial state

From Dev

React + Flux: Getting initial state into a store

From Dev

Redux React create initial state from API

From Dev

react native get async initial state in reducer

Related Related

  1. 1

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

  2. 2

    React parent renders with initial state before successful ajax call sets state

  3. 3

    React - Load Initial List via AJAX

  4. 4

    how to set state in render react native

  5. 5

    React onClick function fires on render

  6. 6

    Axios AJAX call in React returning only initial state

  7. 7

    How can I set initial React state from API data?

  8. 8

    react native - getting state from storage on before render()

  9. 9

    Set ajax-fetched data to component before render

  10. 10

    Alert invoked in React JS componentDidMount lifecycle method pops up before the initial render instead of after

  11. 11

    Load state/data before render?

  12. 12

    Reset to Initial State with React Hooks

  13. 13

    React initial state. counting

  14. 14

    React hooks - set state of Parent from child via function

  15. 15

    Is there a way of capturing element state before MutationObserver mechanism fires (onVisibilityChanged)?

  16. 16

    Make React useEffect hook not run on initial render

  17. 17

    React.js: Refs are not available on initial render

  18. 18

    React CSS animations only after initial render

  19. 19

    how to set initial value in react?

  20. 20

    how to set initial value in react?

  21. 21

    Set initial state for missing key in component data

  22. 22

    Set initial state with multiple async calls in Redux

  23. 23

    Set initial state on RadioGroup without entering OnCheckedChangeListener

  24. 24

    Set initial background color before loading

  25. 25

    Set $rootScope before textAngular directive initial

  26. 26

    React/Redux server side rendering initial state

  27. 27

    React + Flux: Getting initial state into a store

  28. 28

    Redux React create initial state from API

  29. 29

    react native get async initial state in reducer

HotTag

Archive