Why cant react set initial state based on props
Asked Answered
S

2

5

I have a es6 react component that I want the initial value of the state to depend on that of the passed down prop, but its value is always false:

AttachStateToProps component

<AttachStateToProps VALUE=false />

AttachStateToProps component:

class AttachStateToProps extends React.Component {
  state = {
    stateValue: this.props.VALUE,
  }
  render() {
    console.log('Value of Prop - ', this.props.VALUE)
    console.log('Value of State - ', this.state.stateValue)

  return null
  }
}

Every time the value of the prop VALUE is changed, I get:

`Value of Prop - false` // this changes whenever I change prop value in 
   <AttachStateToProps />

and

`Value of State - false` // this does not change accordingly.

I figure it could be something to do with state/setState being async and older getinitialState but I don't get why it.

Serviceberry answered 18/5, 2018 at 4:14 Comment(2)
try changing the state in componentDidMountResemble
now it returns true all the time. Also eslint complains [eslint] Do not use setState in componentDidMount (react/no-did-mount-set-state) - i think its not a good patternServiceberry
A
10

Initializing the state from the props in the constructor, or as a class property, will not update the state when the prop changes. However, react does detect the prop change, and rerenders the component.

Example:

class AttachStateToProps extends React.Component {
  state = {
    stateValue: this.props.VALUE,
  }
  render() {
    console.log('Value of Prop - ', this.props.VALUE)
    console.log('Value of State - ', this.state.stateValue)

  return null
  }
}

const renderWithVal = (val) => ReactDOM.render(
  <AttachStateToProps VALUE={val} />,
  demo
);

renderWithVal(5);
renderWithVal(15);
renderWithVal(115);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="demo"></div>

To update the state when the prop changes, you need to use a component's lifecycle method.

With React ^16.3 you can use the static getDerivedStateFromProps() method to update the state from the props (and initialize it as well):

static getDerivedStateFromProps(nextProps) {    
  return {
    stateValue: nextProps.VALUE,
  }
}

class AttachStateToProps extends React.Component {
  state = {};

  static getDerivedStateFromProps(nextProps) {    
    return {
      stateValue: nextProps.VALUE,
    }
  }
      
  render() {
    console.log('Value of Prop - ', this.props.VALUE)
    console.log('Value of State - ', this.state.stateValue)

  return null
  }
}

const renderWithVal = (val) => ReactDOM.render(
  <AttachStateToProps VALUE={val} />,
  demo
);

renderWithVal(5);
renderWithVal(15);
renderWithVal(115);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="demo"></div>

With React versions prior to 16.3, you can use componentWillReceiveProps().

Note: componentWillReceiveProps is deprecated, but will work 'till version 17.

componentWillReceiveProps(nextProps, prevState) {
  this.setState({
    stateValue: nextProps.VALUE,
  })
}
Amuse answered 18/5, 2018 at 4:44 Comment(0)
H
2

It will not work without super(props) in constructor.

    class AttachStateToProps extends React.Component { 
constructor(props) { 
super(props); 
this.state = { stateValue: this.props.VALUE, 
} 
} 
render() { 
console.log('Value of Prop - ', this.props.VALUE) console.log('Value of State - ', this.state.stateValue) return null 
}
 }
Headband answered 7/7, 2018 at 8:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.