9

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>
        );
    }
}
1
  • 1
    your this points to the map function where no handleClick function definition exists. You need to instantiate a variable with this outside the map and use it inside your map Commented Jun 21, 2018 at 10:10

3 Answers 3

10

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.

Sign up to request clarification or add additional context in comments.

Comments

7

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

Comments

3

You have to use this in map arguments or arrow function.

 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>;
        }, this)

Why?

Read here.

If a thisArg parameter is provided to map, it will be used as callback's this value. Otherwise, the value undefined will be used as its this value.

For a better undestanding of this scope check here. Explains what are in this in different context like Simple function call, as an object method, as arrow function, etc. Also explain how control the scope thanks to bind, call and apply.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.