1

I have refactored a component and i am not using React.createClass in class methods anymore but i have this error now

{this.props.removeComment.bind(null, this.props.params.svgId, i)}

TypeError: Cannot read property 'props' of undefined

The code was perfectly working

Before the refactor

import React from 'react';

const Comments = React.createClass({
  renderComment(comment, i) {
    return (
      <div className="comment" key={i}>
        <p>
          <strong>{comment.user}</strong>
          {comment.text}
          <button className="remove-comment" onClick={this.props.removeComment.bind(null, this.props.params.svgId, i)}>&times;</button>
        </p>
      </div>
    )
  },

  handleSubmit(e) {
    e.preventDefault();
    const { svgId } = this.props.params;
    const author = this.refs.author.value;
    const comment = this.refs.comment.value;
    this.props.addComment(svgId, author, comment);
    this.refs.commentForm.reset();
  },

  render() {
    return (
      <div className="comments">
        {this.props.svgComments.map(this.renderComment)}
        <form ref="commentForm" className="comment-form" onSubmit={this.handleSubmit}>
          <input type="text" ref="author" placeholder="author"/>
          <input type="text" ref="comment" placeholder="comment"/>
          <input type="submit" hidden />
        </form>
      </div>
    )
  }
});

export default Comments;

Now after the refactor

import React from 'react';

export default class Comments extends React.Component {
  renderComment(comment, i) {
    return (
      <div className="comment" key={i}>
        <p>
          <strong>{comment.user}</strong>
          {comment.text}
          <button className="remove-comment" onClick={this.props.removeComment.bind(null, this.props.params.svgId, i)}>&times;</button>
        </p>
      </div>
    )
  };

  handleSubmit(e) {
    e.preventDefault();
    const { svgId } = this.props.params;
    const author = this.refs.author.value;
    const comment = this.refs.comment.value;
    this.props.addComment(svgId, author, comment);
    this.refs.commentForm.reset();
  };

  render() {
    return (
      <div className="comments">
        {this.props.svgComments.map(this.renderComment)}
        <form ref="commentForm" className="comment-form" onSubmit={this.handleSubmit}>
          <input type="text" ref="author" placeholder="author"/>
          <input type="text" ref="comment" placeholder="comment"/>
          <input type="submit" hidden />
        </form>
      </div>
    )
  }
};

So how can i manually bind this in class constructor ?

P. Frank
  • 5,691
  • 6
  • 22
  • 50
Koala7
  • 1,340
  • 7
  • 41
  • 83

2 Answers2

2

you need to bind the methods to the component instance in the constructor like so

export default class Comments extends React.Component {
  constructor() {
    super();

    this.renderComment = this.renderComment.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

if you are using babel with stage-2 you can also refactor your methods and just do the following:

renderComment = (comment, i) => {
  // code goes here    
}

handleSubmit = (e) => {
  // code goes here
}

i prefer the second way as its much cleaner but have to have the right plugin for babel for it to work properly.

What this is doing is making sure when these functions are called, they are called with this being bound to the component.

finalfreq
  • 6,830
  • 2
  • 27
  • 28
  • In this case, you do not even need the parentheses around the `e` :-) – ltamajs Nov 04 '16 at 15:50
  • can you update the component i have pasted to accept the answer? I have tried to bind the methods to the component in the construnctor but i still get the error "Cannot read property 'bind' of undefined @finalfreq – Koala7 Nov 05 '16 at 10:49
  • my bad, answer accepted – Koala7 Nov 05 '16 at 10:55
0

you should have a constructor, call the super() and there bind the method

React.createClass automatically bind this to the component, in ES6 class you have to make it manually, and you can not use this until super() has been called

ltamajs
  • 1,231
  • 11
  • 15
  • 1
    *"ES6 automatically bind `this` to the class, not to the react component."* What is that suppose to mean? ES6 classes to *not* autobind. And the ES6 class *is* the React component. – Felix Kling Nov 04 '16 at 15:54
  • Sorry, I wrote a pointless stuff. I mean, in React.createClass, for example within a `change` event callback `this` would be bound to the component automatically, but in ES6 class, you have to make it manaully and you can not use `this` until `super()` has been called. Is that right? Please correct me, if not – ltamajs Nov 04 '16 at 16:19