Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.js: onClick function from child to parent

I used this article as an example (React way), but it is not working for me. Please point me to my mistake, as I can't understand what's wrong.

This is the error I see:

Uncaught TypeError: this.props.onClick is not a function

Here is my code:

// PARENT
var SendDocModal = React.createClass({
  getInitialState: function() {
    return {tagList: []};
  },
  render: function() {
    return (
      <div>
        {
          this.state.tagList.map(function(item) {
            return (
              <TagItem nameProp={item.Name} idProp={item.Id} onClick={this.HandleRemove}/>
            )
          })
        }
      </div>
    )
  },
  HandleRemove: function(c) {
    console.log('On REMOVE = ', c);
  }
});

// CHILD
var TagItem = React.createClass({
  render: function() {
    return (
      <span className="react-tagsinput-tag">
        <span>{this.props.nameProp}</span>
        <a className='react-tagsinput-remove' onClick={this.HandleRemove}></a>
      </span>
    )
  },
  HandleRemove: function() {
    this.props.onClick(this);
  }
});

Thanks in advance!

like image 459
user2787338 Avatar asked Jul 22 '15 13:07

user2787338


2 Answers

The issue is that this inside the map callback does not refer to the React component, hence this.HandleRemove is undefined.

You can set the this value explicitly by passing a second argument to map:

this.state.tagList.map(function() {...}, this);

Now this inside the callback refers to the same value as this outside the callback, namely the SendDocModal instance.

This has nothing to do with React, it's just how JavaScript works. See How to access the correct `this` context inside a callback? for more info and other solutions.

like image 102
Felix Kling Avatar answered Nov 15 '22 03:11

Felix Kling


Try the following:

    var SendDocModal = React.createClass({
        getInitialState: function() {

            var item = {};
            item.Name = 'First';
            item.Id = 123;

            var item2 = {};
            item2.Name = 'Second';
            item2.Id = 123456;
            return {tagList: [item,item2]};
        },

        HandleRemove: function(c){
            console.log('On REMOVE = ', c);
        },

        render: function() {
            return (<div>
                {this.state.tagList.map(function(item){
                    return(
                            <TagItem nameProp={item.Name} idProp={item.Id} key={item.Id} click={this.HandleRemove}/>
                    )}, this)}
                    </div>
            )       
        }

    });
    // CHILD
    var TagItem = React.createClass({

        handleClick: function(nameProp)
        {
            this.props.click(nameProp);
        },


        render: function(){
            return(
                <span className="react-tagsinput-tag" ><span onClick={this.handleClick.bind(this, this.props.nameProp)}>{this.props.nameProp}</span><a className='react-tagsinput-remove' ></a></span>
            )
        }
    }); 

Few changes:

Added 'this' after the tagList mapping. To be honest I am not entirely sure why - perhaps a more experienced programmer can tell us.

Added a key to each TagItem. This is recommended and an the console will inform you that you should do this so that if the state changes, React can track each item accordingly.

The click is passed through the props. See React js - having problems creating a todo list

like image 39
AndrewB Avatar answered Nov 15 '22 04:11

AndrewB