11

My question is very simple. If I have a class in ES6 is it possible to use an arrow function within it?

import React, { Component } from 'react';

export default class SearchForm extends Component {

  state = {
    searchText: ''
  }

  onSearchChange = e => {
    this.setState({ searchText: e.target.value });
  }

  handleSubmit = e => {
    e.preventDefault();
    this.props.onSearch(this.query.value);
    e.currentTarget.reset();
  }

  render() {
    return (
      <form className="search-form" onSubmit={this.handleSubmit} >
        <label className="is-hidden" htmlFor="search">Search</label>
        <input type="search"
               onChange={this.onSearchChange}
               name="search"
               ref={(input) => this.query = input}
               placeholder="Search..." />
        <button type="submit" id="submit" className="search-button">
          <i className="material-icons icn-search">search</i>
        </button>
      </form>
    );
  }
}

The reason I ask is that I get an error in my console, even when using Babel. It seems like there's a lot of resources on the internet stating you can do this (most of which are about developing with React).

Is this something that Babel should do, and will eventually become natively supported?

The error I get is an unexpected = sign, just before the parens.

EDIT: I forgot to mention, the reason I wish to do this is to make use of the this keyword in context of the class. If I use a regular function - to my understanding - I would have to bind this to the function. I'm trying to look for a nicer way of doing that.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
tomhughes
  • 4,597
  • 2
  • 24
  • 33
  • No, it's not the way things work. The right way is the constructor() {} provided with sample. – adelindev May 20 '17 at 01:16
  • Just out of curiosity, why would you want to? What would be the benefit? – Lennholm May 20 '17 at 01:21
  • Developing with React and wanting to make use of the this keyword without explicitly binding it. – tomhughes May 20 '17 at 01:23
  • See also http://stackoverflow.com/questions/31362292/how-to-use-es6-arrow-in-class-methods - possibly duplicate question – le_m May 20 '17 at 01:35
  • Arrow 'methods' have been proposed (currently stage 1 draft) for inclusion into the standard here: https://tc39.github.io/proposal-class-public-fields/ – le_m May 20 '17 at 01:41
  • 2
    Do NOT use an arrow function for a method that you want `this` to point to the object instance. The arrow function definition will use a lexical `this`, NOT the object `this`. That's just a misuse of an arrow function. It's not just a syntax shortcut - it changes the value of `this` in a way which is inappropriate for nearly all method definitions. An arrow function is simply the WRONG tool for the job when declaring methods. – jfriend00 May 20 '17 at 05:39
  • Regarding a 'nicer' way, see this answer, http://stackoverflow.com/a/43601993/3731501 . The fact that arrows look a bit neater than `bind` doesn't make them nicer. – Estus Flask May 20 '17 at 09:02

3 Answers3

14

In order to do that, you'll need to add the transform-class-properties babel plugin, which allows you to have auto-bound class methods like you are attempting.

Unlike what others have just suggested, there IS value in doing this. Namely, your class function automatically has the class this bound to it, without having to manually bind it in your constructor.

Without the transform-class-properties plugin, you could do:

export default class SearchForm extends Component {

  constructor(props) {
    super(props)
    this.doSomething = this.doSomething.bind(this)
  }

  doSomething () {
    console.log(this) // <-- 'this' is the class instance
  }
}

With the plugin:

export default class SearchForm extends Component {

  doSomething = () => {
    console.log(this) // <-- 'this' is the class instance, no binding necessary
  }
}

Heres and article that explains it (among other thing) fairly well and consisely: https://medium.com/@joshblack/writing-a-react-component-in-es2015-a0b27e1ed50a

Logic Artist
  • 1,006
  • 11
  • 23
  • This is the exact conclusion I've came to before you answered, reason I wanted this to refer to the class is so I can use 'this.setState' and refer to the class itself. – tomhughes May 20 '17 at 01:48
  • Exactly. This is a fairly typical React component pattern – Logic Artist May 20 '17 at 01:50
  • Slightly off topic, but in the same class there is an object defined, i.e. within the class there is state = { ... }. Is this another experimental feature, and how does it differ to using this.state = { ... } within the constructor? – tomhughes May 20 '17 at 01:52
  • Not sure. Could you update your code example to show it? – Logic Artist May 20 '17 at 02:08
  • Have updated, looks like it's instead of using the constructor but I'm not sure? – tomhughes May 20 '17 at 02:12
  • Ah, that actually never occurred to me, but (as long as you're using the transform plugin I mentioned) it should be the same thing. Its just a cleaner way of defining a class property. See http://stackoverflow.com/questions/37788342/is-it-better-to-define-state-in-constructor-or-using-property-initializers – Logic Artist May 20 '17 at 02:23
  • What's the point of declaring a method as an arrow function and then overriding that with an auto-bound method? Doesn't make any sense. Basically arrow functions make no sense for methods where you want `this` to be the object instance. People are trying to use arrow functions because they love the syntax shortcut without paying any attention to what they are good for and not good for. That's what people need to actually learn. – jfriend00 May 20 '17 at 05:38
  • 1
    @jfriend00 When using React I want to use this to modify the class itself, I.e access this.state and be able to access the components state. I'm not sure what you said about the object instance applies here? – tomhughes May 20 '17 at 10:32
0

Yes it is possible to use arrow functions inside ES6 classes. I noticed that you are not calling super inside your constructor you have to do that if you are extending and overriding the constructor.

Other than that your code compiles correctly to ES5, checkout this link to the online Babel transpiler that contains your sample code.

Checkout this question similar to yours.

Community
  • 1
  • 1
Tekeste Kidanu
  • 1,950
  • 2
  • 14
  • 22
  • Even when calling super() I still get the syntax error, it only works when using the 'transform-class-properties' plugin for Babel, not sure why the Babel online transpiler would work unless it already takes that into consideration and uses the plugin? – tomhughes May 20 '17 at 01:45
0

Yes, it is possible. Your code should work, you need to check you Babel setup, there must be something wrong with how it's configured.

In your example, doSomething is actually a property of the class; the type of the property is a function. Here's an example that additionally shows a method, as well as a use of the this keyword:

class SearchForm {

  doSomething = () => {
    console.log('I am a property')
  }

  doSomethingElse() {
    console.log('I am a method')
  }

  doBoth() {
    this.doSomething();
    this.doSomethingElse()
  }
}

const form = new SearchForm();
form.doBoth();

You can check it out live here.

m1kael
  • 2,801
  • 1
  • 15
  • 14
  • This answer does not address anything about using arrow functions to define the methods which is what the question appears to be about. – jfriend00 May 20 '17 at 05:54