moesh
moesh

Reputation: 319

Uncaught TypeError: _this3.chooseTopic is not a function ReactJS

I am getting an issue using react, where I'm trying to click on a list item and invoke a method, chooseTopic, for the class but I'm getting returned "Uncaught TypeError: _this3.chooseTopic is not a function ReactJS"

Here is roughly my class:

class Topicselect extends Component {
    constructor(props){
        super(props);
        this.state = {
            topics: ['math','english','science']
        }
    }
    chooseTopic(){
        console.log('has been clicked')
    }
    render(){
        const topics = this.state.topics.map(function(topic, i){
            return(<li key={i} onClick={() => this.chooseTopic()}>{topic}
            </li>)
        })
        return(
            <div className="topicselect">   
                <ul>
                  <p onClick={()=> this.chooseTopic()}>hello world</p>
                 {topics}
               </ul>
            </div>  
        )
    }
}

export default Topicselect;

when I clicked the hello world paragraph it invokes the function, however when I click the list items it gives me the error, Uncaught TypeError: _this3.chooseTopic is not a function ReactJS

any ideas?

Upvotes: 2

Views: 9615

Answers (3)

Eeshwar Das
Eeshwar Das

Reputation: 1

The this object has no reference. In React, the callback function or event handler does not know that it is part of the react Component class.

this object can be bound or an arrow function syntax used when referencing the callback (event handler).

This concept is presented in React: this is null in event handler.

Not sure if this code will work in your situation. For demonstration purposes:

return(<li key={i} onClick={ this.chooseTopic.bind(this) }>{topic}

or

return(<li key={i} onClick={(e) => this.chooseTopic(e)}>{topic}

You may need to modify the signature of your event handler to accept the event object:

chooseTopic(e){
...

Upvotes: 0

Doug
Doug

Reputation: 15513

You need to bind this

``` constructor(props) { // Other stuff

// This binding is necessary to make this work in the callback this.chooseTopic = this.chooseTopic.bind(this); } ```

You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.

This is not React-specific behavior; it is a part of how functions work in JavaScript. Generally, if you refer to a method without () after it, such as onClick={this.handleClick}, you should bind that method.

If calling bind annoys you, there are two ways you can get around this. If you are using the experimental property initializer syntax, you can use property initializers to correctly bind callbacks:

https://facebook.github.io/react/docs/handling-events.html

Upvotes: 0

Andrew Li
Andrew Li

Reputation: 57974

That's because you're using a function for your Array#map callback. Use an arrow function:

const topics = this.state.topics.map((topic,  i) => {
  return (
    <li key={i} onClick={() => this.chooseTopic()}>
      {topic}
    </li>
  )
})

The reason is because, in a function expression, this won't refer to your component, it depends on how it's called. Since this isn't referring to the component, chooseTopic isn't found as a method thus the error. An arrow function does not bind this and thus refers to the this of the enclosing scope -- the component.

Upvotes: 7

Related Questions