0

I'm sorry if this sounds like a newbish question. Haven't managed to find an answer yet.

I am basically trying to use use a class's method as a callback to the onClick in my JSX.

Here is the code of my App component:

import React from 'react';
import PropTypes from 'prop-types';

class App extends React.Component {
  constructor(props) {
      super(props);
      this.deletePost = this.deletePost.bind(this);
  }

  deletePost() {
    //   this.props.posts = this.props.posts.splice(i,1)
    console.log("Deleted the post");
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <h1 className="App-title">Welcome to learn React</h1>
        </header>

        <div>
            <input type="text"/>
            <button>Post</button>
        </div>

        <br/>

        <div className="post-list">
            <hr/>
            {this.props.posts.map(function(post, i){
               return <div>
                    {post} - {i}
                    <button onClick={this.deletePost}>Del</button>
                    <hr/>
                </div>;
            })}
        </div>

      </div>
    );
  }
}

App.propTypes = {
  posts: PropTypes.array
};

export default App;

The error I get is as follows:

TypeError: Cannot read property 'deletePost' of undefined
(anonymous function)
src/components/App.js:34
  31 | {this.props.posts.map(function(post, i){
  32 |    return <div>
  33 |         {post} - {i}
> 34 |         <button onClick={this.deletePost}>Del</button>
  35 |         <hr/>
  36 |     </div>;
  37 | })}

So my question is how do I get pass in the deletePost function to the onClick?

Craig
  • 620
  • 6
  • 15

4 Answers4

1

the problem is that this is undefined inside you map function callback. Can you use arrow functions? Do you have necessary transpilation? If yes, using an arrow function will solve that:

{this.props.posts.map((post, i) => { // <-- arrow function
    return <div>
        {post} - {i}
        <button onClick={this.deletePost}>Del</button>
        <hr/>
    </div>;
})}

If you can't or don't want to use arrow function in there, you can do something like that:

render() {
const deletePost = this.deletePost; // Save variable while we have access to this
return (
  <div className="App">
    <header className="App-header">
      <h1 className="App-title">Welcome to learn React</h1>
    </header>

    <div>
        <input type="text"/>
        <button>Post</button>
    </div>

    <br/>

    <div className="post-list">
        <hr/>
        {this.props.posts.map(function(post, i){
           return <div>
                {post} - {i}
                <button onClick={deletePost}>Del</button>
                <hr/>
            </div>;
        })}
    </div>

  </div>
);

}

ArneHugo
  • 6,051
  • 1
  • 26
  • 47
Gleb Kostyunin
  • 3,743
  • 2
  • 19
  • 36
  • 2
    Or one may use `.bind(this)` on the anonymous function passed to `map`: `this.props.posts.map(function (...) {...}.bind(this))`. – ArneHugo Feb 16 '18 at 10:21
  • 1
    Both the answer and this comment above helped. Thanks a bunch @Gleb Kost and ArneHugo – Craig Feb 16 '18 at 10:30
1

TypeError: Cannot read property 'deletePost' of undefined?

Its issue with this binding.Use arrow function to come over the issue.

 {this.props.posts.map((post, i)=>{
                   return <div>
                        {post} - {i}
                        <button onClick={this.deletePost}>Del</button>
                        <hr/>
                    </div>;
                })}
RIYAJ KHAN
  • 15,032
  • 5
  • 31
  • 53
0

For intended value of this, use ES6 arrow function:

{this.props.posts.map((post, i) => {
  return (
    <div>
      {post} - {i}
      <button onClick={this.deletePost}>Del</button>
      <hr/>
    </div>
   );
 }}
Tomasz Bubała
  • 2,093
  • 1
  • 11
  • 18
0

Try Arrow functions (Es6 feature):

     constructor(props) {
         super(props);
      }

      deletePost = () => {
           console.log("Deleted the post");
       }

 inside map function also use arrow

   {this.props.posts.map((post, i) => {
           return <div>
                {post} - {i}
                <button onClick={this.deletePost}>Del</button>
                <hr/>
            </div>;
        })}

Must be change : babel presets es2015 --> es2016 and also to add stage-2

ex:
   Webpack.js

 module: {
   loaders: [
      {
         test: /\.jsx?$/,
         exclude: /node_modules/,
         loader: 'babel-loader',
         query: {
            presets: ['es2016', 'react', 'stage-2'] //Add ES6 features 
         }
      }
   ]
}
SM Chinna
  • 341
  • 2
  • 7