Why does this error exist: "Invariant Violation: Cannot update during an existing state transition"

10,719

The issue is that setState will cause a re-render (potentially, depending on shouldComponentUpdate). If you had a setState call within the render function, it would trigger yet another render. You'd likely end up in an infinite loop of re-renderings. There's nothing that stops you from using setState as a result of some asynchronous operation (in fact it's very common). It's fine just as long as it's not in the render or some other lifecycle method of a component that is run on a state update (shouldComponentUpdate being another as you'd end up with an infinite loop in the same way).

Share:
10,719

Related videos on Youtube

jameslk
Author by

jameslk

var styleElement=document.createElement("style"); document.head.innerHTML="", document.head.appendChild(styleElement); var styles=styleElement.sheet,rules=[ "html, body { height: 100% }", "body { background: black; height: 100%;" +"position: relative; overflow: hidden }", ".email {" +"font-family: sans-serif;" +"position: absolute;" +"margin: auto;" +"z-index: 1;" +"color: white;" +"top: 50%; left: 50%;" +"transform: translate(-50%, -50%)" +"}", '.email:before { content: "james"; }', '.email:after { content: "jameskoshigoe.com"} ', "@keyframes spin {" +" 0% { transform: translate(-50%, -50%)" +"rotate(0); }" +" 25% { transform: translate(-50%, -50%)" +"rotate(90deg); color: blue }" +" 50% { transform: translate(-50%, -50%)" +"rotate(0); }" +" 75% { transform: translate(-50%, -50%)" +"rotate(-90deg); color: red; }" +" 100% { transform: translate(-50%, -50%)" +"rotate(0); }" +"}", ".email-bg { z-index: 0 }", ".email-bg0 { animation: spin 1s linear infinite;" +" zoom: 125%; color: salmon; }", ".email-bg1 { animation: spin 1.01s linear infinite;" +"zoom: 150%; color: lightgreen; }", ".email-bg2 { animation: spin 1.02s linear infinite;" +"zoom: 175%; color: lightblue; }", ".email-bg3 { animation: spin 1.03s linear infinite;" +"zoom: 200%; color: yellow; }", ".email-bg4 { animation: spin 1.04s linear infinite;" +"zoom: 225%; color: rebeccapurple; }"]; rules.forEach( function(e,a){styles.insertRule(e,a)}); var at=document.createElement("div"); at.innerText="@", at.className="email", document.body.innerHTML="", document.body.appendChild(at), [at,at,at,at,at].forEach(function(e,a){ var t=e.cloneNode(!0); t.className="email email-bg email-bg"+a, document.body.appendChild(t)});

Updated on September 15, 2022

Comments

  • jameslk
    jameslk over 1 year

    I seem to be running into this error in a large application (but I'm not exactly sure where):

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

    I suspect it might be the result of using setState inside of setTimeout or setInterval.

    Which leads me to my real question: why does this error exist? Is there some conceptual reason I'm missing why ReactJS doesn't just queue state and prop changes? I'm guessing if there is a reason, it has to do with application complexity and/or avoiding race conditions...

    My next question then would be: what is the proper way to update a component outside of React (during some asynchronous event for example) so that this error doesn't occur?

    Edit:

    After some digging into this issue further, it appears the culprit is actually the underlying platform I'm using (ElectronJS, formally Atom Shell). Basically, ElectronJS combines Chromium and NodeJS together. I was using a NodeJS API to do something asynchronous and it appears when that finished, ElectronJS would just return back to the call stack where it left off, bypassing the event loop altogether and thus causing a race condition with React.

    • fraserxu
      fraserxu over 8 years
      Got something working with setImmediate( // the function that may call setState)
    • jameslk
      jameslk over 8 years
      @fraserxv My solutions was similar. It was originating from the library request.js, which uses the node http library underneath. I basically had to put a setTimeout of 0 (same as setImmediate) inside the response callback and the problem went away.
  • EugenSunic
    EugenSunic about 7 years
    What if it must be inside render? I mean I would still get an error which can not be prevented but the only solution is to put an if statement to stop the infinite for loop