In React.js should I make my initial network request in componentWillMount or componentDidMount?

In the react docs it recommends making initial network requests in the componentDidMount method:

componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request. Setting state in this method will trigger a re-rendering.

If componentWillMount is called before rendering the component, isn't it better to make the request and set the state here? If I do so in componentDidMount, the component is rendered, the request is made, the state is changed, then the component is re-rendered. Why isn't it better to make the request before anything is rendered?


You should do requests in componentDidMount.

If componentWillMount is called before rendering the component, isn't it better to make the request and set the state here?

No because the request won’t finish by the time the component is rendered anyway.

If I do so in componentDidMount, the component is rendered, the request is made, the state is changed, then the component is re-rendered. Why isn't it better to make the request before anything is rendered?

Because any network request is asynchronous. You can't avoid a second render anyway unless you cached the data (and in this case you wouldn't need to fire the request at all). You can’t avoid a second render by firing it earlier. It won’t help.

In future versions of React we expect that componentWillMount will fire more than once in some cases, so you should use componentDidMount for network requests.


You should use componentDidMount.

Why isn't it better to make the request before anything is rendered?

Because:

  • Your request will almost certainly not finish before the component is rendered (unless rendering large amounts of markup, or you are on a zero latency quantum entanglement connection), and the component will ultimately need to re-render again, most of the time
  • componentWillMount is also called during server-side rendering (if applicable)

However, if you were to ask, isn't it better to initiate a request in componentWillMount (without actually handling it in place), I would definitely say yes (ES6), and I do this myself to occasionally cut a few milliseconds from load times:

componentWillMount() {
    // if window && window.XMLHttpRequest
    if (!this.requestPromise) {
        this.requestPromise = new Promise(resolve => {
            // ... perform request here, then call resolve() when done.
        });
    }
}

componentDidMount() {
    this.requestPromise.then(data => ...);
}

This will start preloading your request during componentWillMount, but the request is only handled in componentDidMount, whether it is already finished by then or still in progress.


You should make the request in componentDidMount as no side-effects requests should be made in componentWillMount. It's fine to setState in componentWillMount, if you setState in componentDidMount you will immediately trigger a second re-render.

You will read that it's an anti-pattern (UGHHH) and some linters have it prohibited (eslint-react-plugin), but I wouldn't pay huge attention to that as sometimes it's the only way to interact with the DOM. You can set your default state either in willMount or as a method property ( state = { } ), if you're using the associated babel stage

As you say the component will be rendered already once, but this is good because you can display some kind of Loader or any other form of information that a resource is loading.

class MyComp extends Component {

    // What I do with stage 0
    state = { mystate: 1 }

    // What you might want to do if you're not 
    // on the experimental stage, no need to do 
    // the whole constructor boilerplate
    componentWillMount() {
        this.setState({ mystate: 1 });
    }

    componentDidMount() {
        dispatch(yourAction());

        // It's fine to setState here if you need to access 
        // the rendered DOM, or alternatively you can use the ref
        // functions
    }

    render() {
        if (!this.props.myCollection) return <Loader />

        return (
           <div> // your data are loaded </div>
        )
    }
}