0
votes

I have a component where I set initial state for it. When I change, in my case, checkbox state, the parent component should send new property with flag 'true' or 'false' and it does if I console.log it in my render method. However, if I use lifecycle method static getDerivedStateFromProps - it shows me only updated values from previous state and new props (like 'true', 'true' instead of previous 'false', and new 'true'). The question is: Can't figure out, where is the pitfalls here? It sends new props if I console.log it in my render method, but getDerivedStateFromProps shows the same values both in prevState and newProps.

class MyComponent extends React.PureComponent {
 state = {
   stateValue: this.props.myValue
 }

 handleChange = () => {
   // Custom parent method which change checkbox state and send new props to MyComponent
   this.props.onChange(...)
 }

 static getDerivedStateFromProps(nextProps, prevState) {
        const { myNextProperty } = nextProps
        const { myPrevStateProperpty } = prevState
        debugger
        if (myNextProperty !== myPrevStateProperpty) {
            return {
                stateValue: nextProps,
            }
        }
        return null
    }

    render() {
       const { stateValue } = this.state

       return (
           <MyViewComponent onChange={this.handleChange} value={stateValue} />
       )
    }
}

3

3 Answers

0
votes

Try componentDidUpdate and remember that this.props always fresh this.props == nextProps, avoid copying props in the state and when you have to do it you should specify it with defaultProp, ect ...

class Button extends React.PureComponent {
  render() {
    const textColor = slowlyCalculateTextColor(this.props.color);
    return (
      <button className={
        'Button-' + this.props.color +
        ' Button-text-' + textColor // ✅ Always fresh
      }>
        {this.props.children}
      </button>
    );
  }
}

Or better Hooks solution:

function Button({ color, children }) {
  const textColor = useMemo(
    () => slowlyCalculateTextColor(color),
    [color] // ✅ Don’t recalculate until `color` changes
  );
  return (
    <button className={'Button-' + color + ' Button-text-' + textColor}>
      {children}
    </button>
  );
}
0
votes

I am not sure why it didn't work for you maybe because of fields myNextProperty and myPrevStateProperty or because of this.props.onChange function that you didn't provided here. But I implemented your code and it works, you can see in console that the values of prevState and nextProps are different:

https://codesandbox.io/embed/practical-monad-93ztc?fontsize=14&hidenavigation=1&theme=dark

0
votes
state = {
  stateValue: this.props.myValue
}

You're storing myValue in stateValue but comparing something else:

static getDerivedStateFromProps(nextProps, prevState) {
 //   const { myNextProperty } = nextProps
 //   const { myPrevStateProperpty } = prevState
    debugger
    if (myNextProperty !== myPrevStateProperpty) {
        return {
            stateValue: nextProps,
        }
    }
    return null
}

Probably you need something like:

static getDerivedStateFromProps(nextProps, prevState) {
 //   const { myNextProperty } = nextProps
 //   const { myPrevStateProperpty } = prevState
    debugger
    if (nextProps.myValue !== prevState.stateValue) {
        return {
            stateValue: nextProps.myValue,
        }
    }
    return null
}