When you need to fetch some data for a React component, where do you do it?
This question comes up all the time.
There are two common places to fetch data in class components, and both are lifecycle methods:
With the addition of React Hooks, there’s a new place to fetch data with the useEffectHook. Read that article for more on useEffect; in this article I’ll focus on class components.
And just to be clear, the
render function is never a good place to fetch data – or to do anything that’s asynchronous, that changes state in some way, or that causes side effects. The only thing
render should do is return some JSX to display, and maybe spend a few lines preparing that data to display.
Let’s look at the two common options and the pros and cons of the
componentDidMount lifecycle methods.
This looks like the logical place to fetch data. Fetch it just before the component will mount, right?
There are a couple problems though.
First, the big one:
componentWillMount is deprecated as of React 16.3 (March 2018). Until React 17, that name will continue to work – but this is a warning to move away from it as soon as you can. In place of it, you can use the
constructor in a class component. But if you’re currently fetching data in
componentWillMount, keep reading…
Here’s the second “gotcha”, and it’s a bit unintuitive: An API call with
componentWillMount will not return before the first render. This means the component will render with empty data at least once.
componentWillMount to finish whatever it started – React marches on and continues to
There is no way to “pause” rendering to wait for data to arrive. You cannot return a promise from
componentWillMount or wrangle in a
setTimeout somehow. The right way to handle this is to setup the component’s initial state so that even when it renders with no data, it still looks acceptable.
So what can you do? You could render an empty list, or maybe show a little hint to the new user about how to get started. Whatever you do, don’t try to iterate over an array of
undefined or you’ll get the dreaded “Cannot read property ‘map’ of undefined” error.
By the time
componentDidMount is called, the component has been rendered once.
componentDidMount is the best place to put calls to fetch data, for two reasons:
Using didMount makes it clear that data won’t be loaded until after the initial render. This reminds you to set up initial
stateproperly, so you don’t end up with undefined state that causes errors.
If you ever need to render your app on the server (a.k.a. server-side-rendering/SSR with Next.js or similar),
componentWillMountwill actually be called twice – once on the server, and again on the client – which is probably not what you want. Putting your API call code in
componentDidMountwill ensure that data is only fetched from the client, where it should be.
I hope this clears up the question of where to load data. If you’re still not sure of the best way how to actually make the AJAX call and load data, read more about API calls in React.
Learning React can be a struggle -- so many libraries and tools!
My advice? Ignore all of them :)
For a step-by-step approach, read my book Pure React.