Search code examples
javascriptreactjslifecycle

componentWillReceiveProps vs getDerivedStateFromProps


What exactly componentWillReceiveProps 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:

componentWillReceiveProps(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, comp.myState)} 
 checked={myState.indexOf(comp.myState) > -1} />

React version: 16.4.1


Solution

  • 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 (component) 2) on reset button pressed (child component)

    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 component, I found some hints to the differences between componentWillReceiveProps 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 component
          // 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

    • componentWillReceiveProps 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)

    • componentWillReceiveProps responds to the props changes

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

    The process of pasting true value in the state I require because getDerivedStateFromProps handle all the changes unlike componentWillReceiveProps handles only the child component 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.