Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 992
Non Avatar asked Oct 14 '15 17:10

Non


People also ask

How would you prevent a component from rendering?

It is done using stateVariable. The value of the stateVariable determines whether to render the component or not. Its value can be changed by the occurrence of any event like onClick.

How do you stop Rerendering in functional components?

Memoization using useMemo() and useCallback() Hooks. Memoization enables our react code to re-render components only if there is an update in the props. With this approach, developers can avoid unnecessary re-renderings and reduce the computational load in applications.

What causes a component to get re-rendered?

There are four reasons why a component would re-render itself: state changes, parent (or children) re-renders, context changes, and hooks changes. There is also a big myth: that re-renders happen when the component's props change. By itself, it's not true (see the explanation below).

How can you prevent a child component from re-rendering in class component?

React does not care whether “props changed” - it will render child components unconditionally just because the parent rendered! If you don't want a component to re-render when its parent renders, wrap it with memo. After that, the component indeed will only re-render when its props change.


2 Answers

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.

like image 50
Mathletics Avatar answered Oct 24 '22 06:10

Mathletics


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()
    );
  }
});
like image 43
Oliver Fencott Avatar answered Oct 24 '22 06:10

Oliver Fencott