Wronski
Wronski

Reputation: 1596

React: props.itemId returns different value vs variable that uses props.itemId

Currently

I have a child component ItemField (see code below), that takes this.props.itemId from parent component, and does a check to see if this.props.itemId is populated, and populates a new variable this.itemId based on the check i.e.

itemId = this.props.itemId ? this.props.itemId : "new";

Problem

Sorting actions on the App that move the position of items in the list of items around, cause this.props.itemId and this.itemId to return different values confirmed by console logs. this.props.itemId has the correct value, but this.itemId contains the original value of the item at this position.

ItemField.js

class ItemField extends Component {

  constructor(props) {
    super(props);
    this.state = {
      //temp value of inputs
      }
    }

  componentDidMount() {
    //no actions on did mount
  }

  //issueId to be Updated
  //if "new", then a new issue will be updated
  itemId = this.props.itemId ? this.props.itemId : "new";

  render() {
    console.log("this.props.itemId = " + this.props.itemId); //logs "1111"
    console.log("this.itemId = " + this.itemId); //should log "1111" i.e. same as above, but this doesn't always happen

    return (
      <div
        id={this.itemId}
      >{showValue}
      </div>
    )
  }
}

export default ItemField;

Question

I have 2 console.log lines in the above script, that in some situations (e.g. after sorting the item list) return different values. These should always be the same. What are some possible reasons for this?

Notes:

  1. I have tried to move the itemId = this.props.itemId ? this.props.itemId : "new" line into the constructor and into componentDidMount, but this didn't solve the issue.
  2. I am not mapping through all ItemFields in the parent component, but rather explicitly creating a component for each one e.g. <ItemField value={this.props.item.name} itemId={this.props.item.id} /> where name is the field value, and id is the itemId that is passed to all fields.

Component Structure

enter image description here

Upvotes: 1

Views: 870

Answers (2)

Aleks
Aleks

Reputation: 984

̶̶̶M̶̶̶o̶̶̶v̶̶̶e̶̶̶ ̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶ ̶̶̶i̶̶̶n̶̶̶s̶̶̶i̶̶̶d̶̶̶e̶̶̶ ̶̶̶t̶̶̶h̶̶̶e̶̶̶ ̶̶̶s̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶ ̶̶̶A̶̶̶K̶̶̶A̶̶̶ ̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶s̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶ ̶̶̶=̶̶̶{̶̶̶ ̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶:̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶p̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶}̶̶̶ ̶̶̶a̶̶̶n̶̶̶d̶̶̶ ̶̶̶i̶̶̶m̶̶̶p̶̶̶l̶̶̶e̶̶̶m̶̶̶e̶̶̶n̶̶̶t̶̶̶ ̶̶̶ ̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶̶̶̶c̶̶̶o̶̶̶m̶̶̶p̶̶̶o̶̶̶n̶̶̶e̶̶̶n̶̶̶t̶̶̶D̶̶̶i̶̶̶d̶̶̶U̶̶̶p̶̶̶d̶̶̶a̶̶̶t̶̶̶e̶̶̶(̶̶̶p̶̶̶r̶̶̶e̶̶̶v̶̶̶P̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶,̶̶̶ ̶̶̶p̶̶̶r̶̶̶e̶̶̶v̶̶̶S̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶,̶̶̶ ̶̶̶s̶̶̶n̶̶̶a̶̶̶p̶̶̶s̶̶̶h̶̶̶o̶̶̶t̶̶̶)̶̶̶{̶̶̶ ̶̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶i̶̶̶f̶̶̶ ̶̶̶(̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶p̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶ ̶̶̶!̶̶̶=̶̶̶=̶̶̶ ̶̶̶p̶̶̶r̶̶̶e̶̶̶v̶̶̶P̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶)̶̶̶ ̶̶̶{̶̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶s̶̶̶e̶̶̶t̶̶̶S̶̶̶t̶̶̶a̶̶̶t̶̶̶e̶̶̶(̶̶̶{̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶:̶̶̶t̶̶̶h̶̶̶i̶̶̶s̶̶̶.̶̶̶p̶̶̶r̶̶̶o̶̶̶p̶̶̶s̶̶̶.̶̶̶i̶̶̶t̶̶̶e̶̶̶m̶̶̶I̶̶̶d̶̶̶}̶̶̶)̶̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶}̶̶̶ ̶̶ ̶̶ ̶̶̶ ̶̶̶ ̶̶̶ ̶̶̶}̶̶̶̶̶̶

Why do you even need itemId honestly? Just use props directly.

 return (
  <div
    id={this.props.itemId || 'new' }
  >{showValue}
  </div>
)

Upvotes: 1

Junius L
Junius L

Reputation: 16142

It won't update as it runs once, to make sure the two always have the same values move

itemId = this.props.itemId ? this.props.itemId : 'new';

to render or save it in state and use getDerivedStateFromProps to update the value.

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>

<script type="text/babel">
class ItemField extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      //temp value of inputs
      itemId: '',
    };
  }

  componentDidMount = () => {
    //no actions on did mount
    this.setState({
      itemId: this.props.itemId ? this.props.itemId : 'new'
    })
  }


  //issueId to be Updated
  //if "new", then a new issue will be updated

  static getDerivedStateFromProps = (props, state) => {
    // compare props with state data
    // if they are not equal return props
    // or return null
    // more info here https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
    
    if (props.itemId !== state.itemId) {
      return props;
    }
    return null;
  }

  render() {
    console.log('this.props.itemId = ' + this.props.itemId); //logs "1111"
    console.log('this.state.itemId = ' + this.state.itemId); //should log "1111" i.e. same as above, but this doesn't always happen

    return <div id={this.itemId}>{'showValue'}</div>;
  }
}

class App extends React.Component {

  state = {
    id: 1111
  }

  render() {
    return (
      <div>
        <button onClick={() => this.setState({ id: 2233 })}>Update ID</button>
        <ItemField value={'James'} itemId={this.state.id} />
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>

Upvotes: 1

Related Questions