1

I was rewriting the React Tutorial in ES6, and got stuck in tutorial16.js. Whats the proper way to write this es5 in es6 format?

// tutorial16.js
var CommentForm = React.createClass({
  getInitialState: function() {
    return {author: '', text: ''};
  },
  handleAuthorChange: function(e) {
    this.setState({author: e.target.value});
  },
  handleTextChange: function(e) {
    this.setState({text: e.target.value});
  },
  render: function() {
    return (
      <form className="commentForm">
        <input
          type="text"
          placeholder="Your name"
          value={this.state.author}
          onChange={this.handleAuthorChange}
        />
        <input
          type="text"
          placeholder="Say something..."
          value={this.state.text}
          onChange={this.handleTextChange}
        />
        <input type="submit" value="Post" />
      </form>
    );
  }
});

Here is my CommentForm.jsx that I've written in ES6. If I try to type anything in the form, I get this message in the console: Uncaught TypeError: Cannot read property 'setState' of undefined What I'm doing wrong?

import React from 'react';

class CommentForm extends React.Component {

    constructor(props){
        super(props);
        this.state = { author: '', text: '' }
    }

    handleAuthorChange(e){
        this.setState({author: e.target.value});
    };

    handleTextChange(e){
        this.setState({text: e.target.value});
    }

    render(){
        return(
            <form className="commentForm">
                <input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange}/>
                <input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange}/>
                <input type="submit" value="Post" />
            </form>
        );
    }
}

export default CommentForm;
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
KadoBOT
  • 2,944
  • 4
  • 16
  • 34

2 Answers2

1

You are missing binding onChange handlers to the instance. They are being fired in totally different context, where this doesn't point to your CommentForm.

It should be instead:

<input onChange={this.handleAuthorChange.bind(this)} type="text" placeholder="Your name" value={this.state.author} />
<input onChange={this.handleTextChange.bind(this)} type="text" placeholder="Say something..." value={this.state.text} />
Łukasz
  • 35,061
  • 4
  • 33
  • 33
  • There is a onChange on the inputs. Just roll the scroll bar to the right haha – KadoBOT Jan 22 '16 at 00:59
  • You are missing `.bind(this)` part in your code. – Łukasz Jan 22 '16 at 01:54
  • You are right! Thanks! – KadoBOT Jan 22 '16 at 02:20
  • 1
    @KadoBOT You can alternatively also use the pattern `this.handleAuthorChange = this.handleAuthorChange.bind(this)` in the constructor for every event handler. That way, you don’t need to bind the function every time you need it. – poke Jan 22 '16 at 07:45
0

With property initializers (ES6+) it may look like this:

class CommentForm extends React.Component {

    state = {
        author: '', text: ''
    };

    handleAuthorChange = (e) => {
        this.setState({author: e.target.value});
    };

    handleTextChange = (e) => {
        this.setState({text: e.target.value});
    };

    render() {
        return <form className="commentForm">
            <input
                type="text"
                placeholder="Your name"
                value={this.state.author}
                onChange={this.handleAuthorChange}
            />
            <input
                type="text"
                placeholder="Say something..."
                value={this.state.text}
                onChange={this.handleTextChange}
            />
            <input type="submit" value="Post" />
        </form>
    }
}
xCrZx
  • 2,503
  • 1
  • 24
  • 25
  • There's no reason for that render function to be an arrow. The more stuff you use as class properties, the slower your code is going to be. – loganfsmyth Jan 21 '16 at 19:29
  • The reason is just not to bind `this` to render in constructor – xCrZx Jan 21 '16 at 19:34
  • This code didnt worked for me: ERROR in ./app/src/component/comment-form.jsx Module build failed: SyntaxError: /home/ricardo/Documents/Projects/react-es2015-webpack/app/src/component/comment-form.jsx: Unexpected token (5:10) 3 | class CommentForm extends React.Component { 4 | > 5 | state = { | ^ 6 | author: '', text: '' 7 | }; 8 | Here is the link to my repo, with what i have done so far: https://github.com/KadoBOT/react-es2015-webpack – KadoBOT Jan 21 '16 at 19:55
  • why would you call the render function in the constructor? you should never call the render function on your own. that arrow does not make sense to me either...and you do have access to "this" anyway, even without the arrow... – andyrandy Jan 21 '16 at 20:31
  • @xCrZx `this` in render will already be correct because React calls it as an instance method. You don't need it to be bound. – loganfsmyth Jan 21 '16 at 20:50
  • @loganfsmyth Yeah, you are absolutely right, thank you for clearing this moment. – xCrZx Jan 22 '16 at 07:29