简体   繁体   中英

How can I prevent a component from rendering before data is loaded?

I am waiting the props to come up from a store named GetDealersStore , and the way I am fetching that data is with an action where I am doing this:

  componentWillMount () { GetDealersActions.getDealers(); }

I already test the app and componentWillMount() is running before the initial render where I have this

let dealerInfo;
if (this.state.dealerData) {
  dealerInfo = this.state.dealerData.dealersData.map((dealer) => {
    return (<div>CONTENT</div>);
  })
} else {
  dealerInfo = <p>Loading . . .</p>
}

but for the first second you can see <p>Loading . . .</p> <p>Loading . . .</p> <p>Loading . . .</p> in the screen which is the else in the conditional above, and then the rest of the render comes up with return (<div>CONTENT</div>); which is the if in the conditional. So, I guess, this means that the render method has been trigger twice because it keeps waiting for the data coming from the database.

The data from the database is not available at the time of the 1st render, so, how can I fetch that data before the 1st initial render occurs?

You can't do this with a single component. You should follow the Container Component pattern to separate data from rendering.

let DealersContainer = React.createClass({
  getInitialState() {
    return {dealersData: []};
  },
  componentWillMount() {
    GetDealersActions.getDealers();
  },
  render() {
    let {dealersData} = this.state;
    return (<div>
      {dealersData.map((dealer) => {
        let props = dealer;
        return (<Dealer ...props />); // pass in dealerData as PROPS here
      })}
    </div>);
  }
});

Then update your Dealer component to receive props and render the actual content.

My answer is similar to Mathletics', just in more detail.

In this example I've included initialising state of dealerData to null; this is the check that's made to determine whether the data has been returned from the store by the container.

It's verbose, but declarative, and does what you want, in the order that you want, and it will work each time.

const DealerStore = MyDataPersistenceLibrary.createStore({
  getInitialState() {
    return {
      dealerData: null
    };
  },

  getDealers() {
    // some action that sets the dealerData to an array
  }
});

const DealerInfoContainer = React.createClass({
  componentWillMount() {
    DealerStoreActions.getDealers();
  },

  _renderDealerInfo() {
    return (
      <DealerInfo {...this.state} />
    );
  },

  _renderLoader() {
    return (
      <p>Loading...</p>
    );
  },

  render() {
    const { dealerData } = this.state;

    return (
      dealerData
      ? this._renderDealerInfo()
      : this._renderLoader()
    );
  }
});

const DealerInfo = React.createClass({
  getDefaultProps() {
    return {
      dealerData: []
    };
  },

  _renderDealers() {
    const { dealerData } = this.props;

    return dealerData.map(({ name }, index) => <div key={index}>{name}</div>);
  },

  _renderNoneFound() {
    return (
      <p>No results to show!</p>
    );
  },

  render() {
    const { dealerData } = this.props;

    return (
      dealerData.length 
      ? this._renderDealers()
      : this._renderNoneFound()
    );
  }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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