javascript icon indicating copy to clipboard operation
javascript copied to clipboard

Calling setState in componentDidUpdate

Open dlwalsh opened this issue 7 years ago • 11 comments

It might be worth revisiting react/no-did-update-set-state.

Now that componentWillReceiveProps() is being deprecated, componentDidUpdate() is the only "safe" way to detect changes in props and set state accordingly.

The React docs say calling setState() in componentDidUpdate() is permitted, albeit with caveats.

You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition like in the example above, or you’ll cause an infinite loop. It would also cause an extra re-rendering which, while not visible to the user, can affect the component performance.

dlwalsh avatar Jul 30 '18 05:07 dlwalsh

getDerivedStateFromProps?

ljharb avatar Jul 30 '18 06:07 ljharb

The new lifecycle method getDerivedStateFromProps is not a perfect replacement for componentWillReceiveProps as it does not provide access to prevProps.

dlwalsh avatar Jul 30 '18 21:07 dlwalsh

It would be reasonable, in React 16 and later, to modify the rule's behavior so that it does not warn on "safe" usages of setState.

ljharb avatar Jul 30 '18 21:07 ljharb

(this would need to be done in eslint-plugin-react, however, not here)

ljharb avatar Jul 30 '18 21:07 ljharb

The new lifecycle method getDerivedStateFromProps is not a perfect replacement for componentWillReceiveProps as it does not provide access to prevProps.

@dlwalsh, you may want to check this technique from the official React blog but I would suggest to read the entire article -- maybe you can completely avoid usage of getDerivedStateFromProps :)

AlexanderSoliar avatar Jul 31 '18 17:07 AlexanderSoliar

Polluting state with previous props/state really sucks.

dlwalsh avatar Aug 01 '18 01:08 dlwalsh

@dlwalsh yep it sucks, but it's inevitable in some cases. How do you change the state of a component reacting from a change from react-router that pass match through props?

luishdez avatar Nov 09 '18 21:11 luishdez

componentDidUpdate is the appropriate place to put asynchronous server updates so this warning is patently false, misleading and confusing.

nickjuntilla avatar Jun 21 '19 19:06 nickjuntilla

This rule should be removed or modified to check for a condition. The React docs themselves explain how to safely update the state within componentDidUpdate:

You may call setState() immediately in componentDidUpdate() but note that it must be wrapped in a condition React Docs

jdolearydl avatar Aug 21 '19 19:08 jdolearydl

FWIW, I like to outsource lifecycle method work to (other) named methods in order to ensure they remain segmented by concern. This rule only looks for this.setState in the body of the lifecycle method, so you can do this and get no warning (regardless of whether there should be):

 componentDidUpdate(lastProps: Props) {
    this.updateCursorSuggestionIfNeeded(lastProps.data)
  }

  updateCursorSuggestionIfNeeded(lastData: WhateverData) {
    const { data } = this.props
    if (needsUpdate(data, lastData)) {
      // no way for linter to warn here, with or without the above condition
      this.setState(updatedStateForData(data))
    }
  }

Keeps things neat and negates the (in this case, unnecessary) lint warning.

benmosher avatar Sep 04 '19 11:09 benmosher

Above example is typescript, right?. I'd like to know how to use componentDidUpdate from componentWillReceiveProps in Javascript.

VitaminC1211 avatar May 02 '22 01:05 VitaminC1211