0

I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).

the information from these buttons is coming from an array and I'm using .map () to mount the button list.

My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.

How can I solve this?

Thank you.

import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';

import { getLevel, getDiscipline } from '../../functions';

import template from './index.pug';

export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function

  constructor(props){
    super(props);
    this.state = {
      level: getLevel(),
      discipline: getDiscipline(),
      active: '',
      first_click: true,
    }
  }

  changeActive = () => {
    if (this.state.first_click === true) {
      this.setState({
        active: 'active',
        first_click: false
      });
    } else {
      this.setState({
        active: '',
        first_click: true,
      });
    }
  }


  render() {
    return(
<div className="configuration">
      <div className="config-title">
        <i className="ti-settings" />
        <h2>
          <FormattedMessage {...messages.configAssessment} />
        </h2>
      </div>
      <div className="config-items">
        <div className="form-group">
          <label>
            <FormattedMessage {...messages.level} />
          </label>
          <div className="row">
            {this.state.level.map((level, i) => (
              <div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
                <button
                  className={`btn btn-light-gray btn-block ${this.state.active}`}
                  id={level.id}
                  onClick={this.changeActive}
                >
                  {level.level}
                </button>
              </div>
              ))}
          </div>
        </div>
        <div className="form-group">
          <label>
            <FormattedMessage {...messages.discipline} />
          </label>
          <div className="row">
            { this.state.discipline.map((discipline, i) => (
              <div className="col-xs-1 col-md-4 col-lg-3" key={i}>
                <button
                  className={`btn btn-light-gray btn-block ${this.state.active}`}
                  onClick={this.changeActive}
                >
                  {discipline.discipline}
                </button>
              </div>
              ))}
          </div>
        </div>
        <div className="form-group">
          <label>
            <FormattedMessage {...messages.selectQuestion} />
          </label>
          <div className="row">
            <div className="col-xs-1 col-md-4 col-lg-3">
              <button
                className={`btn btn-light-gray btn-block ${this.state.active}`}
                onClick={this.changeActive}
              >
                <FormattedMessage {...messages.typeAutomatic} />
              </button>
            </div>
            <div className="col-xs-1 col-md-4 col-lg-3">
              <button
                className={`btn btn-light-gray btn-block ${this.state.active}`}
                onClick={this.changeActive}
              >
                <FormattedMessage {...messages.typeManual} />
              </button>
            </div>
          </div>
        </div>
        <div className="form-group fg-right">
          <Link className="btn btn-warning" to="#">
            <FormattedMessage {...messages.createAssessment} />
          </Link>
        </div>
      </div>
    </div>
  );
  }
}
Fellipe Abreu
  • 29
  • 1
  • 8
  • Your code is ok for a single button. If you use multiple buttons then update your code and logic.pass a parameter on your changeActive('{lavel.id}') & button render with data-attribute then compare. add active class as a string. remove first_click object from your state. – Ikram Ud Daula Apr 12 '18 at 19:55

3 Answers3

0

The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.

Yash Thakur
  • 1,172
  • 7
  • 14
0

It depends what you need. You can create separate component for button with state.

You can also keep state of each button in react state as an array, and then you can get the state of each button by index.

I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.

dfee
  • 86
  • 1
  • 4
0

Create a separate component for button

class MyButton extends Component {
constructor(props){
    super(props);
    this.state = {
        person: this.props.person
    }
}

buttonActiveHandler = () => {
    let oldStatus = this.props.person.status;
    this.props.person.status = (!oldStatus ? 'active': '');
    this.setState({
        person:this.props.person
    });
}
render() {
    return (
        <button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
    );
}
}
export default MyButton;

Then import button component. use map function to for your code block

<div className={classes.Box}>
     <h4>Lorem, ipsum.</h4>
    {
       this.props.survey.map((person, i) => {
         return (
            <MyButton key={i} person={person}/>
         )
      })
   }
</div>
Ikram Ud Daula
  • 1,213
  • 14
  • 21
  • Hi, @Ikram I've used your solution and it works great. But now another problem that related to your solution. (I am trying to work on it for 4 days) now in .map I have buttons with multiple activation and buttons with single activation. I can separate the multiples from the simple ones. But when I click on a button multiple I need to add a class disable the simple button. Can you help me with this? Thank you so much. – Fellipe Abreu May 07 '18 at 20:15
  • `buttonActiveHandler(){ let filter = this.state.button.filterMultiple; const oldStatus = this.state.button.status; if(filter === '1'){ this.state.button.status = (!oldStatus ? 'active' : ''); } this.setState({ button: this.props.button, }); }` – Fellipe Abreu May 07 '18 at 20:17