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?
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.
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.
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).
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.
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()
);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With