最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - componentWillReceiveProps vs getDerivedStateFromProps - Stack Overflow

programmeradmin3浏览0评论

What exactly ponentWillReceiveProps and getDerivedStateFromProps are subtle question for me. Because, I just came across to an issue while using getDerivedStateFromProps:

// Component 
state = {
  myState: []
}

// Using this method works fine:

ponentWillReceiveProps(nextProps) {
  this.setState({
    myState: nextProps.myPropsState
  })
}

// But using this method will cause the checkboxes to be readonly:

static getDerivedStateFromProps(nextProps,prevProps) {
  const { myPropsState: myState } = nextProps
  return {
    myState
  }
}

// And here's checkbox
<input type="checkbox" id={`someid`} 
 onChange={(e) => this.handleMethod(e, p.myState)} 
 checked={myState.indexOf(p.myState) > -1} />

React version: 16.4.1

What exactly ponentWillReceiveProps and getDerivedStateFromProps are subtle question for me. Because, I just came across to an issue while using getDerivedStateFromProps:

// Component 
state = {
  myState: []
}

// Using this method works fine:

ponentWillReceiveProps(nextProps) {
  this.setState({
    myState: nextProps.myPropsState
  })
}

// But using this method will cause the checkboxes to be readonly:

static getDerivedStateFromProps(nextProps,prevProps) {
  const { myPropsState: myState } = nextProps
  return {
    myState
  }
}

// And here's checkbox
<input type="checkbox" id={`someid`} 
 onChange={(e) => this.handleMethod(e, p.myState)} 
 checked={myState.indexOf(p.myState) > -1} />

React version: 16.4.1

Share Improve this question asked Aug 3, 2018 at 11:26 Bhojendra RauniyarBhojendra Rauniyar 85.6k36 gold badges176 silver badges239 bronze badges 3
  • The parameters passed to getDerivedStateFromProps () are the current props and state and not nextProps and prevProps. It should return the next state depending on the current state and props. Please carefully read the docs at least. – trixn Commented Aug 3, 2018 at 11:34
  • that shouldn't matter here however, parameter name can be anything we wish but I just wrote to pare will receive props. Further, I'm here to why checkboxes are readonly when I use derived state? – Bhojendra Rauniyar Commented Aug 3, 2018 at 11:40
  • How does it help to pare them by naming its parameters with something that they aren't representing? Also unconditionally updating state from props is considered an anti-pattern. – trixn Commented Aug 3, 2018 at 11:47
Add a ment  | 

3 Answers 3

Reset to default 7

getDerivedStateFromProps is not a direct alternative to ponentWillReceiveProps, purely because of the fact that its called after every update, whether its the change in state or change in props or re-render of parent.

However whatever is the case, simply returning the state from getDerivedStateFromProps is not the right way, you need to pare the state and props before returning the value. Else with every update the state is getting reset to props and the cycle continues

As per the docs

getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.

This method exists for rare use cases where the state depends on changes in props over time. For example, it might be handy for implementing a <Transition> ponent that pares its previous and next children to decide which of them to animate in and out.

Deriving state leads to verbose code and makes your ponents difficult to think about. Make sure you’re familiar with simpler alternatives:

If you need to perform a side effect (for example, data fetching or an animation) in response to a change in props, use ponentDidUpdate lifecycle instead.

If you want to re-pute some data only when a prop changes, use a memoization helper instead.

If you want to “reset” some state when a prop changes, consider either making a ponent fully controlled or fully uncontrolled with a key instead.

P.S. Note that the arguments to getDerivedStateFromProps are props and state and not nextProps and prevProps

To get into more details,

In order to make changes based on props change, we need to store prevPropsState in state, in order to detect changes. A typical implementation would look like

static getDerivedStateFromProps(props, state) {
    // Note we need to store prevPropsState to detect changes.
    if (
      props.myPropsState !== state.prevPropsState
    ) {
      return {
        prevPropsState: state.myState,
        myState: props.myPropsState
      };
    }
    return null;
  }

Finally, I resolved my issue. It was a painful debugging:

// Child Component

// instead of this
// this.props.onMyDisptach([...myPropsState])

// dispatching true value since myPropsState contains only numbers
this.props.onMyDispatch([...myPropsState, true])

This is because, I have two conditions: 1) on checkbox change (ponent) 2) on reset button pressed (child ponent)

I was needing to reset the states when reset button is pressed. So, while dispatching state to the props for reset button, I used a boolean value to know it's a change from the reset. You may use anything you like but need to track that.

Now, here in the ponent, I found some hints to the differences between ponentWillReceiveProps and getDerivedStateFromProps after debugging the console output.

// Component
static getDerivedStateFromProps(props, state) {
    const { myPropsState: myState } = props
    // if reset button is pressed
    const true_myState = myState.some(id=>id===true)
    // need to remove true value in the store
    const filtered_myState = myState.filter(id=>id!==true)
    if(true_myState) {
      // we need to dispatch the changes to apply on its child ponent
      // before we return the correct state
      props.onMyDispatch([...filtered_myState])
      return {
        myState: filtered_myState
      }
    }
    // obviously, we need to return null if no condition matches
    return null
  }

Here's what I found the results of the console output:

  • getDerivedStateFromProps logs immediately whenever props changes

  • ponentWillReceiveProps logs only after child propagates props changes

  • getDerivedStateFromProps doesn't respond to the props changes ( I meant for the dispatch changes as in the example code)

  • ponentWillReceiveProps responds to the props changes

  • Thus, we needed to supply the changes to child ponent while using getDerivedStateFromProps.

The process of pasting true value in the state I require because getDerivedStateFromProps handle all the changes unlike ponentWillReceiveProps handles only the child ponent dispatches the changes to the props.

By the way, you may use custom property to check if it is changed and update the value if getDerivedStateFromProps but for some reason I have to tweak this technique.

There might be some confusion on my wording but I hope you'll get it.

From the react docs:

Note that this method is fired on every render, regardless of the cause. This is in contrast to UNSAFE_ponentWillReceiveProps, which only fires when the parent causes a re-render and not as a result of a local setState.

You are effectively overriding your state with the current props every time after calling setState(). So when you check a box (e) => this.handleMethod(e, p.myState) is called which is assume calls setState() to update the checked state of the checkbox. But after that getDerivedStateFromProps() will be called (before render) that reverts that change. This is why unconditionally updating state from props is considered an anti-pattern.

发布评论

评论列表(0)

  1. 暂无评论