React.js: Where to fetch my data?

componentWillMount() vs componentDidMount()

Tj Hubert
Tj Hubert
Aug 26, 2017 · 2 min read

React components have many useful lifecycle hooks in order to initiate a component with remote data. On a first glance, componentWillMount()(a.k.a. extension of the constructor()) might seem to be the perfect place to do so and, truthfully, there is nothing wrong with that. However, realizing the asynchronous behavior of fetching data from a remote server, on the first render, react will render the component with an empty data. The data fetching has not been resolved yet! A lot of times I have fallen to Cannot read property ‘map’ of undefined trap as I expected the first render to happen after my fetch resolves.

In order to be more explicit about when the data actually arrives, data fetching can be placed in componentDidMount(). This approach immediately leads developers (or, well, at least me) to handle the case where the data to be rendered is empty.

{ this.props.data &&
this.props.data.map(...)
}

Container and Presentational components

For even further abstraction of handling asynchronous data fetching, a component can be separated into presentational and container components. Container component is responsible for fetching data from remote server and presentational component will just render the data passed from the container component via props. With this approach, not only initializing data that can be removed from the presentational component, but also updating data or when new props are received by the component. If the presentational component does not have an internal state, it can be written without extending the React’s Component class at all.

UserInfoContainer.js

export class UserInfoContainer extends Component {
constructor() {
super();
}

componentDidMount() {
this.props.fetchData(this.props.userId);
}
componentWillReceiveProps(nextProps) {
if (this.props.userId !== nextProps.userId) {
this.props.fetchData(nextProps.userId)
}
}
render() {
return this.props.data
? <UserInfo data={this.props.data}/>
: null;
}
}

UserInfo.js

export const UserInfo = ({data}) => {
return (
<div>
{ data.map( (val, index) => {
<span key={index}>{val}</span>
}
</div>
)
}

)
Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade