Warning: setState(...): Cannot update during an existing state transition

Description

From time to time, seemingly at random, the JS Console of a Stripes application will emit this message:

Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.

Why does it happen? What are the consequences? How can we prevent it?

CSP Request Details

None

CSP Rejection Details

None

Potential Workaround

None

Checklist

hide

TestRail: Results

Activity

Show:

Niels Erik NielsenJanuary 12, 2017 at 12:51 PM
Edited

Nice job.

So it comes down to the order of execution of constructors and life cycle methods when wrapping one React component inside another. Here's a log showing the order with Trivial (which calls itself About sometimes) wrapped in Wrapper:

So the order is: Wrapper constructor - Wrapper componentWillMount - Trivial constructor - Trivial componentWillMount - Trivial componentDidMount - Wrapper componentDidMount

So by putting the createReducers in Wrapper.componentWillMount (instead of Wrapper.componentDidMount which is too late or Wrapper.constructor which causes the warning), the reducers will be ready for use in Trivial.componentWillMount or DidMount.

Mike TaylorJanuary 12, 2017 at 12:20 PM

This seems to work fine – the Trivial module (and indeed Users) is unaffected, and the warning is gone.

Mike TaylorJanuary 12, 2017 at 12:04 PM

I wonder if we should move the reducer code back to componentWillMount just to shut up the warning, now we're confident we understand what it's doing and why it's benign. But when we did something like that before, it broke the Trivial module – see https://folio-org.atlassian.net/browse/STRIPES-36

But for some reason which he now can't remember. Niels-Erik moved the code to componentDidMount on the previous occasion. I'll try componentWillMount and see if that works better.

Mike TaylorJanuary 12, 2017 at 11:51 AM

I think what we have here is a confusion on the part of the React developers. They are concerned with two things:

  1. It's bad to call setState from render.

  2. It's not always a great idea to cause side-effects from a constructor, and the constructor for connected components sort of does that, a bit.

The first is clearly right, and the second is much fuzzier. But because a single message is used for both conditions, the warning makes it seem that we are doing the much scarier first thing when in fact we are only doing the relatively benign latter.

Mike TaylorJanuary 12, 2017 at 11:44 AM

Generally, the idea is that it's bad for a component's constructor to call setState on itself, changing its own state. And I think that's what the warning was originally introduced to warn about.

But that's not really what we're doing here. When we make a Stripes-Connect wrapper component, we update the reducer of the application's Redux store, which is held in the <Root> component's props.store. That seems perfectly legitimate, and the constructor seems like the conceptually right place to do it, since it is part of what's entailed in making the component ready for use.

Done

Details

Assignee

Reporter

Labels

Priority

TestRail: Cases

Open TestRail: Cases

TestRail: Runs

Open TestRail: Runs

Created January 12, 2017 at 10:12 AM
Updated January 12, 2017 at 12:58 PM
Resolved January 12, 2017 at 12:20 PM
TestRail: Cases
TestRail: Runs