Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reactjs: How to fetch data to loaded before the component is mounted?

Something weird is happening, I've been reading the React docs and they talk about the lifecycle and how you can do somestuff before your component is rendered. I am trying, but everything I try is failing, always the component makes the render first and after calls componenWillMount, ..didMount, etc.. and after the call of those functions, the render happens again.

I need to load the data first in order to fill the state because I don't want initial state to be null, I want it with data since the initial rendering.

I am using Flux and Alt, here is the

action

@createActions(flux)
class GetDealersActions {

  constructor () {
    this.generateActions('dealerDataSuccess', 'dealerDataFail');
  }

  getDealers (data) {
    const that = this;
    that.dispatch();
    axios.get(`${API_ENDPOINT}/get-dealers/get-dealers`)
      .then(function success (response) {
        console.log('success GetDealersActions');
        that.actions.dealerDataSuccess({...response.data});
      })
  }
}

then the store

@createStore(flux)
class GetDealersStore {

  constructor () {
    this.state = {
      dealerData : null,
    };
  }

  @bind(GetDealersActions.dealerDataSuccess)
  dealerDataSuccess (data) {
    this.setState({
      dealerData : data,
    });
  }

}

and the component

@connectToStores
export default class Dealers extends Component {

  static propTypes = {
    title : React.PropTypes.func,
  }

  static contextTypes = {
    router : React.PropTypes.func,
  }

  constructor (props) {
    super(props);
    this.state = {
      modal : false,
      dealerData : this.props.dealerData,
    }
  }

  componentWillMount () {
    GetDealersActions.getDealers();
    this.setState({
      dealerData : this.props.dealerData.dealersData,
    })
  }

  static getStores () {
    return [ GetDealersStore ];
  }

  static getPropsFromStores () {
    return {
      ...GetDealersStore.getState(),
    }
  }

  render () {

    return (<div>
          <div style={Styles.mainCont}>
            {!!this.props.dealerData ?
              this.props.dealerData.dealersData.map((dealer) => {
                return (<div>HERE I AM RENDERING WHAT I NEED</div>);
              }) : <p>Loading . . .</p>
            }
          </div>
      </div>
    );
  }

}

as you can see in the component part I have this

  constructor (props) {
    super(props);
    this.state = {
      modal : false,
      dealerData : this.props.dealerData,
    }
  }

  componentWillMount () {
    GetDealersActions.getDealers();
    this.setState({
      dealerData : this.props.dealerData.dealersData,
    })
  }

which is telling me that dealerData is undefined or can not read property of null.

All I need is to know a technique where I can fetch the data before the initial renders occurs. So I can filled out the state and the start working with that data.

like image 992
Non Avatar asked Oct 12 '15 22:10

Non


2 Answers

React does guarantee that state assignments in componentWillMount will take place before the first render. As you well stated in the comments:

Invoked once, both on the client and server, immediately before the initial rendering occurs. If you call setState within this method, render() will see the updated state and will be executed only once despite the state change.

However, the asynchronous actions requested there will not immediately update your store. Calling GetDealersActions.getDealers(); will issue that the store is updated with new content, but the response will only arrive later in the event queue. This means that this.props.dealersData does not change during the function and setState will attempt to read property "dealersData" of an undefined property. Regardless, the requested content cannot be visible at the first render.

My advice is the same as the one in a similar question. Preventing the component from rendering that content until it becomes available, as you did, is an appropriate thing to do in a program. Alternatively, render a loader while your "dealersData" hasn't arrived.


For solving your particular problem, remove that setState from componentWillMount. All should work well if your parent component is properly listening for changes and propagating them to the children's props.

componentWillMount () {
  GetDealersActions.getDealers();
}
like image 111
E_net4 stands with Ukraine Avatar answered Oct 26 '22 02:10

E_net4 stands with Ukraine


The best answer I use to receive data from server and display it

constructor(props){
        super(props);
        this.state = {
            items2 : [{}],
            isLoading: true
        }

    }

componentWillMount (){
 axios({
            method: 'get',
            responseType: 'json',
            url: '....',

        })
            .then(response => {
                self.setState({
                    items2: response ,
                    isLoading: false
                });
                console.log("Asmaa Almadhoun *** : " + self.state.items2);
            })
            .catch(error => {
                console.log("Error *** : " + error);
            });
    })}

 render() {
   return(
       { this.state.isLoading &&
                    <i className="fa fa-spinner fa-spin"></i>

                }
                { !this.state.isLoading &&
            //external component passing Server data to its classes
                     <TestDynamic  items={this.state.items2}/> 
                }
         ) }
like image 22
Asmaa Almadhoun Avatar answered Oct 26 '22 02:10

Asmaa Almadhoun