comiventor
comiventor

Reputation: 4122

Unable to provide react component method as prop callback to another functional component

I am learning reactjs and built a sample app similar to the tic toe app from on reactjs official website.

When I run the app below and click on one of the choice buttons, it says Uncaught TypeError: Cannot read property 'setAnswered' of undefined. I can't see the difference between the way I have hooked on an instance method to onClick vs the way tic toe app did it. What am I missing?

import React from 'react';
import ReactDOM from 'react-dom';

function Choice(props) {
    return (
        <li> 
            <button onClick={props.onClick}>
                {props.value}
            </button>
        </li>
    );
}

class ChoiceList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      choices: null,
      answered: false,
    };
  }

  setAnswered() {
    this.setState({
        choices: this.state.choices,
        answered: true});
  }

  renderChoice(choice) {
    return <Choice key={choice} value={choice} onClick={() => this.setAnswered()}/>;
  }

  showData(payload) {
    const answered = false;
    const choices = payload.choices;
    this.setState({choices: choices, answered: answered});
  }

  componentDidMount() {
    this.showData({choices: ['Good', 'Bad']});
  }

  render() {
    if (!this.state.choices) {
      return null;
    }
    return (
      <div id="choices">
      <ul id="unsortedList">
        {this.state.choices.map(this.renderChoice)}
      </ul>
      </div>
    );
  }
}

ReactDOM.render(
  <Question />,
  document.getElementById('root')
);

Upvotes: 1

Views: 46

Answers (3)

mbarish-me
mbarish-me

Reputation: 957

This is how your constructor should be, You have to bind the 'this' context to setAnswered .

 constructor(props) {
    super(props);
    this.setAnswered = this.setAnswered.bind(this);
    this.state = {
      choices: null,
      answered: false,
    };
  }

Upvotes: 0

Zhli
Zhli

Reputation: 380

Append the following code to the constructor

constructor(props) {
  super(props);
  this.state = {
    choices: null,
    answered: false,
  };

  this.setAnswered = this.setAnswered.bind(this);
  this.renderChoice = this.renderChoice.bind(this);
  this.showData = this.showData.bind(this);
}

Check the link for your reference Function.prototype.bind()

Upvotes: 1

Martin Reiche
Martin Reiche

Reputation: 1672

This is because "this" is bound to the onClick function in your Choice element and not to your component class. The following should work:

renderChoice(choice) {
  return <Choice key={choice} value={choice} onClick={this.setAnswered.bind(this)}/>;
}

Upvotes: 0

Related Questions