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.
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.
try this for get the index:
const index = counters.findIndex(x => x.id === counter.id);
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
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>
)
}
]