Automa Sha
Automa Sha

Reputation: 51

ReactJS: Cannot read property 'value' of undefined

I am trying to play around with react's child to parent communication, i am passing three buttons which has unique ids, I want to simply display the values after increment button is clicked. On first click, every button does increment fine, however, after second click on any button it gives

Cannot read property 'value' of undefined

. I am not sure what is happening after first click.

    let data = [
      {id: 1, value: 85},
      {id: 2, value: 0},
      {id: 3, value: 0}
    ]

    class Counter extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          counter: 1,
          data: this.props.data
        }
      }


      componentWillReceiveProps(nextProps) {
        if(nextProps !== this.state.data) {
          this.setState({data: nextProps})
        }
      }

       handleClick(id) {
        this.props.increment(id, 
          this.state.data[id-1].value = this.state.data[id-1].value + 
          this.state.counter);
      }

      render() {
        return (
           <div>
              {data.map(data => {
                return (
                  <div key={data.id}>
                    {data.value}
                    <button onClick={() => this.handleClick(data.id)}>+</button>
                  </div>
                )
              })}
           </div>
        )
      }

    }


    class App extends React.Component {
      constructor() {
        super();
        this.state = {
          data
        }
      }

      onIncrement(id, newValue) {
        this.setState((state) => ({
          data: state.data[id-1].value = newValue
        }))
      }

      render() {
        return (
          <div>
           <Counter data={this.state.data} increment={this.onIncrement.bind(this)}/>
          </div>
        )
      }
    }

    ReactDOM.render(
      <App />,
      document.querySelector("#root")
    )

Upvotes: 1

Views: 302

Answers (4)

Vikash_Singh
Vikash_Singh

Reputation: 1896

I found the issue, you have wrongly implemented componentWillReceiveProps and onIncrement , i have corrected these two functions :

onIncrement(id, newValue) {
   let data = this.state.data;
   data[id-1].value = newValue;
   this.setState({data})
}

componentWillReceiveProps(nextProps) {
    if(nextProps.data !== this.props.data) {
      this.setState({data: nextProps.data})
    }
}

Also see the working demo here : https://repl.it/@VikashSingh1/TemporalReliableLanserver

Upvotes: 0

Muhammad Asad
Muhammad Asad

Reputation: 1782

The problematic thing in your code is this line

this.state.data[id-1].value = this.state.data[id-1].value + this.state.counter);

what exactly you want to do here ? because you have 3 index 0,1,2 and you are out of index the it's undefined and you got error mention your requirement here.

your code using state in useless manner and i just optimize your code in a good way. Tip: do not use state-full component where not required use function component. it's working fine and serve according to your need.

    const Counter = (props) => {
    return (
        <div>
            {props.data.map(d => {
                return (
                    <div key={d.id}>
                        {d.value}
                        <button onClick={() => props.increment(d.id, (d.value + 1))}>+</button>
                    </div>
                )
            })}
        </div>
    )
}
class App extends React.Component {

    state = {
        data: [
            { id: 1, value: 85 },
            { id: 2, value: 0 },
            { id: 3, value: 0 }
        ]
    }
    onIncrement = (id, newValue) => {
        debugger
        var newdata = [...this.state.data];
        var d = { ...newdata[id - 1] };
        d.value = newValue;
        newdata[id - 1] = d;
        this.setState({ data: newdata })
    }

    render() {
        return (
            <div>
                <Counter data={this.state.data} increment={this.onIncrement} />
            </div>
        )
    }
}

ReactDOM.render(
    <App />,
    document.querySelector("#root")
)

Upvotes: 1

RK_oo7
RK_oo7

Reputation: 527

import React from 'react';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1,
      data: this.props.data
    };
  }

  handleClick(id, index) {
    this.props.increment(
      id,
      (this.props.data[id - 1].value =
        this.props.data[id - 1].value + this.state.counter), index
    );
  }

  render() {
    return (
      <div>
        {this.props.data.map((data
         , index) => {
          return (
            <div key={data.id}>
              {data.value}
              <button onClick={() => this.handleClick(data.id, index)}>+</button>
            </div>
          );
        })}
      </div>
    );
  }
}

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      data: [{ id: 1, value: 85 }, { id: 2, value: 0 }, { id: 3, value: 0 }]
    };
  }

  onIncrement(id, newValue, index) {
    let {data} = this.state;
  data[index].value = newValue;
    this.setState({
      data
    });
  }

  render() {
    console.log(this.state.data)
    return (
      <div>
        <Counter
          data={this.state.data}
          increment={this.onIncrement.bind(this)}
        />
      </div>
    );
  }
}

please take a look you are doing state updation in wrong way

Upvotes: 0

Cespejo
Cespejo

Reputation: 414

At this sentence:

this.props.increment(id, 
      this.state.data[id-1].value = this.state.data[id-1].value + 
      this.state.counter);

You are doing id-1, i think you don't need that, just [id]. In case you are click button with id 1 your are trying to increment value of 1 - 1 and you haven't any data with id 0

Upvotes: 1

Related Questions