PawełG
PawełG

Reputation: 83

onCLick event on mapped array's element

The thing is to get a clickable html tags made from an array mapped and only clicked element triggered by the onClick event:

class Elements extends Component {
        constructor(props) {
            super(props);
            this.state = {
                backgroundColor: 'pink'
            }
        }
        click = (e, i) => {
            this.setState({
                backgroundColor: 'blue'
            });
        }
        render() {
            let buttons = ['one','two','three','four'];
            return (
                <div>
                    {
                        buttons.map( (e, index) => {
                            return (
                                <button key={index}
                                        style={this.state.style}
                                        onClick={this.click}> {e} </button> 
                                              // e => this.click(e, i)?
                            );
                        } )
                    }
                </div>
            )
        }
    }

this probably can be resolved by using e.currentTarget.style.... or using onClick method with individual option (here 'i') transmitted but I don't understand the logic behind these methods and don't know how to apply them correctly. Anybody?

Upvotes: 1

Views: 1752

Answers (1)

Tholle
Tholle

Reputation: 112777

You could keep an an object in your state named e.g. backgroundColors that contains key/value pairs representing a button and its background color. If the button doesn't have a key in this object, you can fallback to pink.

You can use a new inline arrow function to send the button name to the event handler, like you outlined in your comment.

Example

class Elements extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      buttons: ["one", "two", "three", "four"],
      backgroundColors: {}
    };
  }

  click = button => {
    this.setState(prevState => ({
      backgroundColors: {
        ...prevState.backgroundColors,
        [button]: "blue"
      }
    }));
  };

  render() {
    const { buttons, backgroundColors } = this.state;

    return (
      <div>
        {buttons.map(button => {
          return (
            <button
              key={button}
              style={{ backgroundColor: backgroundColors[button] || "pink" }}
              onClick={() => this.click(button)}
            >
              {button}
            </button>
          );
        })}
      </div>
    );
  }
}

ReactDOM.render(<Elements />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

You could also use a data-* property if you absolutely don't want to use a new inline function in the render method.

Example

class Elements extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      buttons: ["one", "two", "three", "four"],
      backgroundColors: {}
    };
  }

  click = event => {
    const { button } = event.target.dataset;
    this.setState(prevState => ({
      backgroundColors: {
        ...prevState.backgroundColors,
        [button]: "blue"
      }
    }));
  };

  render() {
    const { buttons, backgroundColors } = this.state;

    return (
      <div>
        {buttons.map(button => {
          return (
            <button
              key={button}
              style={{ backgroundColor: backgroundColors[button] || "pink" }}
              data-button={button}
              onClick={this.click}
            >
              {button}
            </button>
          );
        })}
      </div>
    );
  }
}

ReactDOM.render(<Elements />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions