TypeError: this.props.updateCommentText is not a function

I have been following a tutorial for react. Everything went fine but now I get an error I cannot seem to solve. Help is greatly appreciated.

I am trying to edit the text variable for a Comment however when I try to call the function it gives the following error.

error: TypeError:
this.props.updateCommentText is not a function

Board class:

class Board extends React.Component{
  constructor(props){
    super(props);
    this.state = {
        comments: [
          "Hello1",
          "Hello2",
          "Hello3",
        ],
    };
  }
  getInitialState() {
    return {comments: [
      "Hello1",
      "Hello2",
      "Hello3",
    ]}
  }

  removeComment(i){
    var arr = this.state.comments;
    arr.splice(i, 1);
    this.setState({comments: arr})
  }

  updateComment(i, newText){
    var arr = this.state.comments;
    arr[i] = newText;

  }

  eachComment(text, i){
    return(
      <Comment key={i} index={i} updateCommentText={this.updateComment.bind(this)} deleteFromBoard={this.removeComment}>
        {text}
      </Comment>);
  }

  render(){
    return(
      <div className="board">
        {this.state.comments.map(this.eachComment.bind(this))}
      </div>
    )
  }
}

Comment class:

    class Comment extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      editing : false,
      text : "",
    };
  }

  getInitialState() {
    return {editing: false}
  }
  edit() {
    this.setState({editing: true});
  }

  remove() {
    console.log('delete');
    this.props.deleteFromBoard(this.props.index)
  }

  save() {
    var text = this.refs.newText.value;
    this.props.updateCommentText(this.props.index, text);
    this.setState({editing: false});
  }

  renderNormal(){
    return(
      <div className="commentContainer">
        <div className="commentText">{this.props.children}</div>
        <button onClick={this.edit.bind(this)} className="button-primary">Edit</button>
        <button onClick={this.remove} className="button-primary">Remove</button>
      </div>
    );
  }

  renderForm(){
    return(
      <div className="commentContainer">
        <textarea ref="newText" defaultValue={this.props.children}></textarea>
        <button onClick={this.save.bind(this)} className="button-primary">Save</button>
      </div>
    );
  }

  render(){
      if(this.state.editing){
        return this.renderForm();
      }else{
        return this.renderNormal();
      }
  }
}

2 answers

  • answered 2017-06-17 19:05 Yuri Ramos

    First things first: In your Board Component you are declaring getInitialState and Constructor at the same time, they are practically the same thing. Contructor is the new sintax of react, getInitialState is depracated.
    Second, avoid the use of bind inline, declare in your constructor. So in your Board Class would be better if ypu rewrite your constructor like this:

      constructor(props){
        super(props);
        this.state = {
            comments: [
              "Hello1",
              "Hello2",
              "Hello3",
            ],
        };
        this.updateComment = this.updateComment.bind(this);
        this.removeComment=this.removeComment.bind(this);
      }
    

    And the last, and probaly your error, you need to pass the context to your props, inside Board component.

      <Comment key={i} index={i} updateCommentText={this.updateComment(i, text)} deleteFromBoard={this.removeComment(i)}>
            {text}
          </Comment>);
    

  • answered 2017-06-17 19:05 Krasimir

    That's indeed weird. I can't say why you are getting this error. It looks like everything is wired properly and I tried the code above. I was able to hit the save button without seeing this error. However, there are couple of things that should be changed:

    • removeComment is missing a bind in deleteFromBoard prop
    • remove in Comment also does not have a binding.
    • Try to avoid using bind in render functions. This means that you are binding every time when a component is rendered. Do this in the constructor once.
    • You don't have to pass the index. Just use this.updateComment.bind(this, i). This will make updateComment partially executed. (in this case you have to use bind there).
    • In updateComment you are mutating the state but you are not calling setState. There really should be this.setState({ comments: arr }). Without that you are not seeing the edits.