5

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!

2
  • What exactly isn't working? Commented Jul 22, 2015 at 14:01
  • Whoops! sorry.I always get an error: Uncaught TypeError: this.props.onClick is not a function Commented Jul 22, 2015 at 14:02

2 Answers 2

11

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.

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

8 Comments

Hi, Felix. Thanks for your reply. Tried without for loop(just a component with hardcoded props) and it worked great. But I don't understand how to pass the context in my case. Could you please describe this in more detail?
Sorry, simply confused forEach and map. It's the same solution. Have a look at the link in my answer to learn more about this.
If I understood right I should do something like this: code {this.state.tagList.map(function(item){ return( <TagItem nameProp={item.Name} idProp={item.Id} contextProp={this} onClick={this.HandleRemove}/> ) }, this)}, but in this case I get the same : Uncaught TypeError: this.props.contextProp.props.onClick is not a function
No, just implement the solution in my answer. The body of the callback stays the same.
aha, now I got it. the correct code will be: code {this.state.tagList.map(function(item){ return( <TagItem nameProp={item.Name} idProp={item.Id} onClick={this.HandleRemove}/> ) }, this)}
|
1

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

2 Comments

Yeah, the same as Felix advised. slightly more detailed. Thanks a lot, will try to understand "this" concept, looks so different from Java...

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.