Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React onClick function in map function

I try to trigger an onClick event in a map function, and I get this error :

TypeError: Cannot read property 'handleClick' of undefined

How do we trigger an onClick event in a map function ?

Here is my code :

class Component extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isToggleOn: true,
        };
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        this.setState((prevState) => ({
            isToggleOn: !prevState.isToggleOn,
        }));
    }

    render() {
        if (this.props.data) {
            var recipes = this.props.data.map(function (recipe, i) {
                return (
                    <div
                        key={i}
                        className="col-8 offset-col-1 f-l relative m-t-10"
                    >
                        <div className="col-6 f-l">
                            <p className="col-8 f-l">{recipe.title}</p>
                            <button className="f-l" onClick={this.handleClick}>
                                Voir la recette
                            </button>
                        </div>
                    </div>
                );
            });
        }
        return (
            <div className="RecipeList">
                <div className="col-12">
                    {recipes}
                    <div className="both"></div>
                </div>
            </div>
        );
    }
}
like image 646
Pierre Météyé Avatar asked Jun 21 '18 10:06

Pierre Météyé


2 Answers

Use an arrow function as the function given to map instead and this will be what you expect:

if (this.props.data) {
  var recipes = this.props.data.map((recipe, i) => {
    return <div key={i} className="col-8 offset-col-1 f-l relative m-t-10">
      <div className="col-6 f-l">
        <p className="col-8 f-l">{recipe.title}</p>
        <button className="f-l" onClick={this.handleClick}>Voir la recette</button>
      </div>
    </div>;
  });
}

Why this is the case is explained in detail here. Arrow functions don't provide their own this binding, but instead retains the this value of the enclosing lexical context.

like image 64
Tholle Avatar answered Sep 22 '22 01:09

Tholle


This is how I would tackle a similar situation.

import React from "react";
import ReactDOM from "react-dom";

const stuff = ["one", "two", "three"];

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isToggleOn: true
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(val) {
    console.log(val);
  }

  getStuff() {
    var elements = stuff.map((value, key) => {
      return (
        <li key={key} onClick={() => this.handleClick(value)}>
          {value}
        </li>
      );
    });

    return elements;
  }
  render() {
    return <ul>{this.getStuff()}</ul>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

here is the sandbox -> https://codesandbox.io/embed/1rqw081oj7

like image 32
Kavindu Wijesuriya Avatar answered Sep 20 '22 01:09

Kavindu Wijesuriya