How to handle state of multiple buttons with react?

15,204

I have created a simple example for you:

class App extends React.Component {
    constructor() {
        super();
        this.onClick = this.onClick.bind(this);
        this.state = {
            arr: [
                { name: "first", isActive: true },
                { name: "second", isActive: true },
                { name: "third", isActive: true },
                { name: "fourth", isActive: true }
            ]
        };
    }
    onClick(index) {
        let tmp = this.state.arr;
        tmp[index].isActive = !tmp[index].isActive;
        this.setState({ arr: tmp });
    }
    render() {
        return (
            <div>
                {this.state.arr.map((el, index) =>
                    <div key={index} onClick={() => this.onClick(index)}>
                        name: {el.name} / isActive: {el.isActive ? "true" : "false"}
                    </div>
                )}
            </div>
        );
    }
}

Check the fiddle and implement it in your case.

One more way to handle this is keeping the index of an active button in the state:

class App extends React.Component {

state = {
    users: [
    { name: "John" },
    { name: "Sarah" },
    { name: "Siri" },
    { name: "Jim" },
    { name: "Simon" },
  ],
  activeIndex: 0,
}

render() {
    const { users, activeIndex } = this.state;

    return (
      <div>
        {users.map((u, i) => (
          <div
            className={i === activeIndex ? 'active' : ''}
            onClick={() => this.setState({ activeIndex: i })}
            key={u.name}
          >
            {u.name}
          </div>
        ))}
      </div>
    )
  }
}

https://jsfiddle.net/846tfe3u/

Share:
15,204
Chris O
Author by

Chris O

Creative Developer @ Vibrant Media

Updated on June 08, 2022

Comments

  • Chris O
    Chris O almost 2 years

    I have a bootstrap grid where each grid item is populated from an array of objects but after each grid item I would like to have a vote button. How could I achieve this with maintaining state on each button separately, ie when button 1 is clicked the text should change from 'vote' to 'voted' whilst the others remain as 'vote'.

    At the moment when a button is clicked, all of them change to 'Voted'

    class Items extends Component {
        constructor(props) {
            super(props);
            this.state = { hasVoted: false };
    
            this.OnClick = this.OnClick.bind(this);
        }
    
        OnClick() {
            this.setState(prevState => ({
                hasVoted: !prevState.hasVoted
            }));
        }
    
        render() {
            const Item = teasers.items.map(item =>
                <Col key={item.nid}>
                    <span>
                        {itemType}
                    </span>
    
                    <a href={item.path}>
                        <Image src={item.image.src} title={item.productType} />
                        <span>
                            {item.Title}
                        </span>
                        <div className={teasersStyle.copy}>
                            {" "}{item.Copy}>
                        </div>
                    </a>
    
                    <div
                        className={this.state.hasVoted ? "active" : "notactive"}
                        onClick={this.OnClick}
                    >
                        {this.state.hasVoted ? "Voted" : "Vote"}
                    </div>
                </Col>
            );
            return (
                <div>
                    <Grid>
                        <Row>
                            {Item}
                        </Row>
                    </Grid>
                </div>
            );
        }
    }
    
    export default Items;