'React Click Counter: Updating State of just one element
This should be pretty simple, but I can't figure out how to do it.
I have a component with multiple buttons, each with a "count" value, set with state. When a user clicks, the count goes up.
Right now, when I click one of the buttons, both counters change. How can I make it so only the div that was clicked updates, using the same state?
Edit: I don't want to have different counts, as I'd like for this component to render buttons dynamically. What if I don't know how many buttons I'll have at first?
class Block extends React.Component {
state = {
count: 0
};
handleClick = e => {
const count = this.state.count;
this.setState({ count: count + 1 });
};
render() {
return (
<div>
<button className="block" onClick={this.handleClick}>
<div className="counter">{this.state.count}</div>
</button>
<button className="block" onClick={this.handleClick}>
<div className="counter">{this.state.count}</div>
</button>
</div>
);
}
}
Solution 1:[1]
This is more of an issue of learning how to think in react.
If you need to be able to reuse a piece of functionality like a counter, you can make it its own component and have it manage its own state. Then you can reuse it wherever you need.
Here's an example:
class Counter extends React.Component {
state = {
count: 0
};
handleClick = () => {
// Use updater function when new state is derived from old
this.setState(prev => ({ count: prev.count + 1 }));
};
render() {
return (
<button className="block" onClick={this.handleClick}>
<div className="counter">{this.state.count}</div>
</button>
);
}
}
// Now you can use it dynamically like this:
class Block extends React.Component {
render() {
return (
<div>
<div>There are 4 counter component instances that each manage their own state.</div>
{[1,2,3,4].map(v => <Counter />)}
</div>
);
}
}
ReactDOM.render(<Block />, document.getElementById('root'));
<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>
<div id="root"></div>
Solution 2:[2]
you should define two state and when press each button update the current state and you can render the current state in the dome like this
state = {
firstCount: 0,
secondCount: 0
}
and write your action (function) to handle update state like this
handleUpdateCount = stateName => {
this.setState({
[stateName]= this.state[stateName] + 1
})
}
then you should called this function like this =>
this.handleUpdateCount('firstCount')
Solution 3:[3]
If your buttons are dynamic you can set your state to be an array and update the relevant index
class Block extends React.Component {
state = [];
handleClick = index => {
this.setState(state => {
const newState = [...state]; //keep state immutable
!newState[index] && (newState[index] = 0)
newState[index]++
return newState
});
};
render() {
return (
<div>
{[1,2,3].map((value, index) => <button className="block" onClick={() => this.handleClick(index)}>
<div className="counter">{this.state[index]}</div>
</button>)}
</div>
);
}
}
Solution 4:[4]
You have to use another value to update function when new state is derived from old state (like increment)
import React, { Component } from 'react'
export class Ref3 extends Component {
constructor(props) {
super(props)
this.state = {
count:0
}
}
//use prevState to help you update the old value to a new one
clickHandler=()=>{
this.setState((prevState=>({
count:prevState.count+1
})))
}
render() {
return (
<div>
<button onClick={this.clickHandler}>Click To Count</button>
{this.state.count}
</div>
)
}
}
export default Ref3
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | amir hosein Hesarakii |
Solution 3 | NirG |
Solution 4 | Ahmad Abdelfattah |