Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

best place to fetch data before rendering in react

Tags:

reactjs

redux

I would like to know where I should fetch my data in the react life cycle. I tried to put my data in the componentDidMount()and componenWillMount() but without succes...

componentWillMount(){
   
 // this fetch the data from back-end set a store state with the payload
        this.props.fetchUser(); 
        this.setState({userData:this.props.auth});
}

//fetchMethod
export const fetchUser = () => async dispatch =>{//using redux-thunk


    const res= await axios.get('/api/current_user')

    dispatch({type:FETCH_USER, payload:res.data}); 
    
    

};

in my render function I tried to use fetched userData by calling this.state.userData. but it's undefined. I also tried to get it by calling the correct store state, also without succcess. The thing I don't get is, according to my localstorage that store state is defined. Hope someone can tell me what I have done wrong.thanks!

like image 801
Dave_888 Avatar asked May 31 '18 19:05

Dave_888


1 Answers

You can do the fetch in the componentWillMount or the componentDidMount lifecycle methods (with the caveat being that when you have a server rendered application you will get issues of syncing your server rendered html and your rehydrated html if you make the request in the componentWillMount.)

The reason why your this.state.userData is undefined is because the call for your data is asynchronous in nature. I recommend adding functionality to your component to check if the api call is being made (isLoading perhaps?), and if it is completed (isLoaded perhaps?).

In terms of implementation, it would go something like this, assuming you use the connect react-redux higher order component:

class YourComponent extends React.Component {

  componentDidMount() {
    this.props.fetchUser();
  }

  render() {
    const { isLoading, isLoaded, data } = this.props;
    if (isLoading) return <Loader />; // Or whatever you want to return when it is loading
    if (!isLoaded || !data) return null; // If it is not loading and its not loaded, then return nothing.
    return (
      <div>
        <h1>{data.name}</h1>
        <h2>{data.id}</h2>
      </div>
    )
  }

}

const mapStateToProps = state => ({
  isLoading: state.user.isLoading,
  isLoaded: state.user.isLoaded,
  userData: state.user.data
});

export default connect(mapStateToProps, { fetchUser })(YourComponent);

In your action dispatcher/middleware you will need to account for the start of the asynchronous call. Assuming that is accounted for with something like redux thunk...

const initialState = {
  isLoaded: false,
  isLoading: false,
  data: {},
}

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_USER:
      return {
        ...state,
        isLoading: true,
      }
    case FETCH_USER_SUCCESS:
      return {
        isLoading: false,
        isLoaded: true,
        data: action.payload
      };
    default:
      return state;
  }
};

export default reducer;
like image 125
Yo Wakita Avatar answered Sep 22 '22 17:09

Yo Wakita