1

Expected effect: click button -> call function add -> add object this.color to array products- property colors in component App. Example: colors: [{color:" green "}, {color:" black "}] -> colors: [{color: "green"}, {color: "black"}, {color: "red "}]

Error: TypeError: Cannot read property 'push' of undefined

App

class App extends React.Component {
  state = {
    products: [
      { id: 0, colors: [{color:"green"}, {color:"black"}], desc: "some desc" },
      { id: 1, colors: [{color:"yellow"}, {color:"purple"}], desc: "some desc1" }
    ],
    index: null
  };


  add = (newColor) => {
    let newProducts = [...this.state.products]
    newProducts[index].colors.push(newColor);
    this.setState({products: newProducts});
  }

   select = (index) => {
    this.setState({
      index: index
    })
  }


  render() {
    <div>
      <ul>
        {
          this.state.products.map((product, index) => (
            <Product
              key={product.id}
              product={product}
              select={() => this.select(index)}
            />
          ))
        }
      </ul>
      <Details
        add={this.add}
      />
    </div>
  }
}

Details

class Details extends React.Component {

  click1 = () => {
      this.color = {
          color: 'red'
      }

      this.props.add(this.color);
  }



  render() {
    <div>
        <button onClick={this.click1}></button>
    </div>
  }
}

2 Answers 2

2

Change this line:

newProducts[this.state.index].colors.push(newColor);

But also, you should use the callback pattern for setState if you're going to set state based on previous state, so:

this.setState(prevState => {
  let newProducts = [...prevState.products];
  newProducts[prevState.index].colors.push(newColor);
  return {products: newProducts};
});
Sign up to request clarification or add additional context in comments.

2 Comments

Do I have to use newProducts[prevState.index] ? Is it necessary? Maybe it should be: newProducts[this.state.index] ? Look at user Orar's answer
Calls to setState are batched, so relying on this.state.index may not be what you think it is when the update is applied.
0

Your index is undefined. So it's accessing an array element of index undefined.

 const arr = [3, 2]
 arr[undefined] === undefined // true

So I will

 add = (newColor) => {
   const { index } = this.state;

   if (index) {
     this.setState(prevState => {
       const newProducts = [...prevState.products];
       newProducts[index].colors.push(newColor);

       return { products: newProducts };
     });
   }
 }

1 Comment

Maybe should be: newProducts[prevState.index] ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.