question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Triggering async data request in ES6 "constructor()" or "componentWillMount()" or "componentDidMount()"

See original GitHub issue

(I’m fairly new to React and Redux, and so I’m still trying to figure out the best coding patterns and practices, so apologies if this is obvious to everybody but me.)

I’m working on a React/Redux app which has several components which request their own data. For example, when a “/users” route is invoked, the <Users /> component gets invoked, and that component triggers an async call (via redux-thunk) which updates the Redux store with the fetched user data, and then ultimately the users data appears within the <Users /> component.

The render() function within <Users /> is just watching for changes to this.props. The parent of <Users /> watches the Redux store, and of course passes the user data down.

This all worked fine in React 0.13. Or at least it “worked” with no errors/warnings in the console. I updated to 0.14 late last week, and started to see the following warning in the logs:

Warning: setState(…): Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.

I floundered around, and finally figured out that the problem was that my async data request was in the class constructor. Something like this:

constructor(props) {
    super(props);
    fetchUsers();
}

render() {
    return ( do the stuff to output the user data );
}

If I moved the fetchUsers() call to either componentDidMount() or componentWillMount(), everything functioned properly, and the error went away.

So my question is ultimately this: what is going on here? What is the functional difference between these three functions? My (obviously incorrect) assumption was that I should request the data when the class gets initialized, which is why I put the async call in constructor(). Why does that not work, why do those two React lifecycle methods work, and which one of the two is preferable? React’s docs say componentDidMount() is the right method to use, but I would think I’d want the data before the component is mounted, which make me think componentWillMount() should be the method I use.

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:25
  • Comments:24 (11 by maintainers)

github_iconTop GitHub Comments

22reactions
gaearoncommented, Oct 15, 2015

My reaction to this is that perhaps I wish there were documentation somewhere about when constructor() and componentWillMount() should be used in React.

Just don’t execute side effects in constructor. It’s only for initializing state (and perhaps other variables). Don’t make calls or change the state of your app from there.

The question is, regarding the sample app I posted, what are the two components in question? You said a dispatch() in one component triggers a setState() in another component. In my example, is that App and Users?

A route change caused dispatch which caused mounting Users which caused another dispatch in its the constructor. So, dispatch inside connect(Users) caused a setState inside connect(App).

And why did dispatch() in one component cause a setState() in another? Is that due to a bad coding pattern, or something internal to React?

Any time you call dispatch(), all connect()-ed component wrappers have their setState() called so that the connected component receive that new state as their props. It’s just how React Redux works.

14reactions
gaearoncommented, Oct 15, 2015

This is not a bug in React Redux.

This happens when dispatch() inside one component’s constructor causes a setState() inside another component. React keeps track of the “current owner” for such warnings—and it thinks we’re calling setState() inside the constructor when technically constructor causes a setState() inside some other part of the application.

I don’t think we should handle this—it’s just React trying its best do its job. The solution is, as you correctly noted, to dispatch() inside componentWillMount() instead.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Integrating api's in React JS-Constructor vs ... - Medium
Triggering async data request in ES6 "constructor()" or "componentWillMount()" or… (I'm fairly new to React and Redux, and so I'm still trying ...
Read more >
constructor vs componentWillMount; what a ... - Stack Overflow
According to React docs: componentWillMount() is invoked immediately before mounting occurs. It is called before render( ), therefore setting ...
Read more >
React.Component
componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you ......
Read more >
Where to Fetch Data: componentWillMount vs ... - Dave Ceddia
There are two common places to fetch data in class components, and both are lifecycle methods: componentWillMount; componentDidMount.
Read more >
A comprehensive guide to data fetching in React
The Fetch API provides a fetch() method defined on the window object, as well as a JavaScript interface for accessing and manipulating HTTP ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found