Home > other >  How to increment the value of an object within state React
How to increment the value of an object within state React

Time:04-24

So I have this component called counters where the state looks something like this

state = {
    counters: [
      { id: 1, value: 0 },
      { id: 2, value: 3 },
      { id: 3, value: 0 },
      { id: 4, value: 0 },
    ],
  };
  

And I'm trying to increment the value every time a corresponding button is clicked. This is the function I wrote for it.

  handleIncrement = (counter) => {
    const counters = [...this.state.counters];
    const index = counters.indexOf(counter);
    counters[index] = { ...counter };
    counters[index].value  ;
    this.setState({ counters });
  };

It doesn't work. And here are some additional observations.

  1. When I console.log the local counters object (copied from state.counters) it returns an additional row at the end with id: -1 and value: NaN
  2. The variable counter (thats being passed as a parameter) is from a child component. It's supposed to return 0 if the first button is clicked, 1 if the second button is clicked and so on. When I console.log it it seems to be returning the correct values.

by the looks of it, the problem seems to lie in the line

const index = counters.indexOf(counter);

As the value of index is always returned as -1.

CodePudding user response:

You can use the index for updating the corresponding record in the array.

const idx = this.state.counters.findIndex((counter) => counter.id === id);

Complete implementation:-

import React from "react";
import "./styles.css";

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

  handleClick = (id) => {
    const idx = this.state.counters.findIndex((counter) => counter.id === id);
    const counters = [...this.state.counters];
    counters[idx] = { ...counters[idx], value: counters[idx].value   };
    this.setState(counters);
  };

  render() {
    return (
      <div>
        {this.state.counters.map((counter) => (
          <div>
            <button onClick={() => this.handleClick(counter.id)}>
              Button {counter.id}
            </button>
            <span>Value {counter.value}</span>
            <hr />
          </div>
        ))}
      </div>
    );
  }
}

Codesandbox - https://codesandbox.io/s/musing-black-cippbs?file=/src/App.js

CodePudding user response:

try this for get the index:

const index = counters.findIndex(x => x.id === counter.id);

CodePudding user response:

Adding my answer here just in case another confused soul stumbles upon it.

Although it seemed that the problem lied within line

const index = counters.indexOf(counter);

It actually was in the child component where the function was being invoked. Within the parameter I was passing counters.value whereas the handleincrement function within the parent component was expecting not the value, rather the complete object.

The code in its working condition is as below Parent Component:

import React, { Component } from "react";
import Counter from "./counter";

class Counters extends Component {
  state = {
    counters: [
      { id: 1, value: 0 },
      { id: 2, value: 3 },
      { id: 3, value: 0 },
      { id: 4, value: 0 },
    ],
  };
  
  
    handleIncrement = (counter) => {
    const counters = [...this.state.counters];
    const index = counters.indexOf(counter);
    console.log(index);
    counters[index] = { ...counter };
    counters[index].value  ;
    this.setState({ counters });
  };

Child Component:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React, { Component } from "react";

class Counter extends Component {

render() {
    return (
<button
          onClick={() => this.props.onIncrement(this.props.counter)}
          className="btn btn-secondary btn-sm"
        >
          Increment
        </button>
        
        )
        }
        
        
]

  • Related