Is it possible to use arrow functions in classes with ES6? - javascript

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.

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

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.

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.

Related

react javascript arrow function without arrows?

I don't understand how this can work in javascript
renderMarkButton(type, icon) {
it looks like an arrow function, but without the arrows. Here's the context:
class HoverMenu extends React.Component {
renderMarkButton(type, icon) {
const { editor } = this.props
return (
<div className="editorButton"
onMouseDown={event => this.onClickMark(event, type)}>
<FontAwesomeIcon color="#666" active={isActive}
className="editorButton" icon={icon} />
</div>
)
}
render() {
return (
<div>
{this.renderMarkButton('bold', {...faBold})}
</div>
)
}
}
I'm also confused by the
const { editor } = this.props
which comes from Slate, I believe. I would have expected this.props to be {type,icon} in this case.
Regarding your questions:
renderMarkButton(type, icon) { is just the es6 class syntax:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
const { editor } = this.props is called "destructuring". You can read about that here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
hope that helps :)
Arrow and bound methods are useful for passing them as callbacks to be called later:
<Component onClick={this.clickHandler}/>
This isn't the case for renderMarkButton because it's called in a place where it's used with correct this context:
this.renderMarkButton('bold', {...faBold})
renderMarkButton is class prototype method. It doesn't work like arrow function because it isn't bound to the context. Calling it with wrong context would result in error because there would be no this.props object:
const unboundFunction = this.renderMarkButton;
unboundFunction('bold', {...faBold});
This is a special syntax according to new class keyword which will let you create classes.
Basically, those are methods of that specific class and you can't define any other method outside of the class using that specific syntax.
For more information, consider MDN as your best partner.

Binding this on method receiving parameters

I have an event handler which calls a fat arrow function to run a method.
import React, { Component } from 'react';
class App extends Component {
sayHi = msg => {
console.log(msg);
};
render() {
return (
<div>
<button onClick={() => this.sayHi('Hi')}>Console Hi!</button>
</div>
);
}
}
export default App;
I´m learning about contexts and bind() and, I want to convert this example to bind this. My problem is with the parameter that I´m passing when the fat arrow function executes the method, aka, 'Hi'
Is there a way to keep something like this...
<button onClick={this.sayHi('Hi')}>Console Hi!</button>
I tried different ways without good results. Mostly, focused on
constructor(props) {
super(props);
this.sayHi = this.sayHi.bind(this);
}
sayHi = () => {
console.log(msg);
};
And yes... I don´t want to move the 'Hi' to the method or constructor.
I´m trying to learn and understand. I will appreciate any kind of help or orientation.
You are mixing things. There are two cases for your situation and you are trying to use them both.
Binding to this
When do you need you bind your function to this? If you are calling your function in callback like your button (one of the cases of course) and you need to use this in this function then you need to bind it. If you don't use this then there is no need to bind it either.
sayHi() {
console.log("hi");
};
render() {
return (
<div>
<button onClick={this.sayHi}>Console Hi!</button>
</div>
);
}
}
Here, you don't need to bind it, also you can use the function with its reference since there is no argument.
constructor(props) {
super(props);
this.state = {
name: "foo",
}
this.sayHi = this.sayHi.bind(this);
}
sayHi() {
console.log(this.state.name);
};
render() {
return (
<div>
<button onClick={this.sayHi}>Console Hi!</button>
</div>
);
}
}
Here you are using this in the function, so you need to bind it in the constructor or define it as an arrow function.
Your situation
Now, your situation: You are defining your function as an arrow one, no need to bind it anymore if you will use this there. But you are not using it, then no need to use an arrow function. Also, you need to pass an argument to it. So, you need to find a way to accomplish this.
The first method, use an arrow function for onClick. Since if you don't use a callback here you can't use click.
sayHi(msg) {
console.log(msg);
};
render() {
return (
<div>
<button onClick={() => this.sayHi("hi")}>Console Hi!</button>
</div>
);
}
}
If you use like this.sayHi("hi") then this function is invoked in the first render, not with a click.
You can use .bind here as a second method also.
sayHi(msg) {
console.log(msg);
};
render() {
return (
<div>
<button onClick={this.sayHi.bind(null,"hi")}>Console Hi!</button>
</div>
);
}
}
See, we use bind but did not use this since we don't need it. We are not using this in our sayHi function.

React binding this to a class method

So i'm reading a book on React which said I have to bind my methods like
this.onClickMe = this.onClickMe.bind(this);
but it looks to work just fine without using the above code
class ExplainBindingsComponent extends Component {
onClickMe() {
console.log(this);
}
render() {
return (
<button
onClick={ () => { this.onClickMe() } }
type="button"
>
Click Me
</button>
);
}
}
but it's saying I should do something like this,
class ExplainBindingsComponent extends Component {
constructor() {
super();
this.onClickMe = this.onClickMe.bind(this);
}
onClickMe() {
console.log(this);
}
render() {
return (
<button
onClick={this.onClickMe}
type="button"
>
Click Me
</button>
);
}
}
is this.onClickMe = this.onClickMe.bind(this); still something I have to do? and if so what does it do vs my above example
There are multiple ways to bind your function to the lexical context of the React class,
one such method is to bind it in the constructor,
other method is to use class fields as arrow functions, and
the third way to bind in the render using .bind or arrow,
Each of these can be used, however its best to avoid binding in the render since a new function is returned on each render
Using class field as arrow function.
class ExplainBindingsComponent extends Component {
onClickMe = () => {
console.log(this);
}
render() {
return (
<button
onClick={ this.onClickMe }
type="button"
>
Click Me
</button>
);
}
}
Binding in render
onClick={() => this.onClickMe() }
or
onClick={this.onClick.bind(this)}
is this.onClickMe = this.onClickMe.bind(this); still something I have to do?
You don't have to do it if you use arrow functions that capture lexical this. But it is considered to be a best practice because it allows you to avoid function creation inside render.
render() {
return (
<button
/* creates new function on every render call*/
onClick={ () => { this.onClickMe() } }
type="button"
>
Click Me
</button>
);
}
vs
constructor() {
super();
// creates function once per component instance
this.onClickMe = this.onClickMe.bind(this);
}
In your case, you don't need to because you use arrow function where this is bound to a context in which arrow function is defined - in this case to your component.
this.onClickMe = this.onClickMe.bind(this)
it's necessary when you pass function without any binding so it might be invoked where this will point to another object.
For anyone who is following 'React Step by Step' link and got stuck because in the example Clock, they haven't written any bind and it has worked well, but on the next example Toggle, they started to use bind(this).
Well, you can see the function tick(){...} (Clock class) and handleClick (){...} (Toggle class) are similar, as they both use the word this inside. Well the difference between them is how they are called. In the first (Clock), it is called using arrow function (inside componentDidMount() method) and using it allows you to bind automatically the word this with the object. On the other hand, the second method is not using ()=>{}, and need to bind this with the object. So for this purpose the assignment this.handleClick = this.handleClick.bind(this); helps you.
There are 3 ways to bind this
While defining the state. Like this:
this.state = {
this.eventHandler = this.eventHandler.bind(this)
}
Change the normal function to arrow function. Like this:
eventHandler = () => {
console.log('event handler');
}
Pass arrow function directly into the props. Like this:
<input onClick={(e) => this.eventHandler(e) } />
Hope this could resolve your problem.
~RDaksh

How can I fix 'warning Expected 'this' to be used by class method ' eslint error?

I am creating a PDF like this inside a react Component.
export class Test extends React.PureComponent {
savePDF() {
const source = document.getElementById('printContainer');
/* eslint new-cap: ["error", { "newIsCap": false }]*/
let pdf = new jspdf('p', 'pt', 'letter');
let margins = { top: 50,
left: 60,
width: 612
};
pdf.fromHTML(
source,
margins.left,
margins.top,
{
width: margins.width
},
() => {
pdf.save('worksheet.pdf');
}
);
}
and I am getting warning Expected 'this' to be used by class method 'savePDF' class-me
this is being called an click like this onClick={this.savePDF} see below
render() {
<Link
name="save-to-pdf"
onClick={this.savePDF}
button="secondary">
Save to PDF</Link>
<div id="printContainer" className="cf-app-segment--alt cf-hearings-worksheet">...
There are two different answers to this question, depending on how you want to handle it.
First, the reason you get this error is because of the ESLint rule https://eslint.org/docs/rules/class-methods-use-this. Specifically, this is because if something is a class method, e.g. if you are calling this.foo() to call a function, the whole reason to make it a method is because there are properties on this that you need to use.
While in many languages with class, most functions are methods, that is not the case in JS. If you have a class like
class Example {
constructor(){
this.data = 42;
}
someMethod() {
this.someHelper(this.data);
}
someHelper(value){
console.log(value);
}
}
the someHelper function would trigger the same error you are getting, because it never uses this, so you can just as easily do
class Example {
constructor(){
this.data = 42;
}
someMethod() {
someHelper(this.data);
}
}
function someHelper(value){
console.log(value);
}
In your case, you can do this. Your whole savePDF function could be moved outside of the class object.
That said, it is important to ask yourself why something like this isn't using this. In most cases, you'd expect any function that works with HTML to absolutely use this, because how else, in React, is it supposed to access the element's that React has created.
So the real answer to your question would be to drop the
const source = document.getElementById('printContainer');
line. If you need access to the HTML element being created by React, you should be using React's APIs to do so. That would be done with something like
class SavePDFButton extends React.Component {
constructor(props) {
super(props);
this.printContainer = null;
this.savePDF = this.savePDF.bind(this);
this.handlePrintContainerRef = this.handlePrintContainerRef.bind(this);
}
render() {
return (
<div>
<Link
name="save-to-pdf"
onClick={this.savePDF}
button="secondary"
>
Save to PDF
</Link>
<div
id="printContainer"
className="cf-app-segment--alt cf-hearings-worksheet"
ref={this.handlePrintContainerRef}
/>
</div>
);
}
handlePrintContainerRef(el) {
// When React renders the div, the "ref={this.handlePrintContainerRef}" will
// make it call this function, which will store a reference.
this.printContainer = el;
}
savePDF() {
// OLD: const source = document.getElementById('printContainer');
const source = this.printContainer;
// ...
}
}
I believe that's caused by the class-methods-use-this ESLint rule.
It's just letting you know that your function doesn't use this, so you can probably make it a static function.
turn it into static function
static savePDF() { ... }
Its happening because this function isnt using this meaning it dosnt need to be dynamic

OnClick Event binding in React.js

I would like to pass the parent div id, on click of that div or any child element of the same div. But I am unable to achieve it. Please tell me where I am making a mistake. Code is below:
viewMore: function(i,j){
console.log('You clicked: ', i );
},
render : function(){
var attributeId = "groups_";
attributeId+= index;
return(
//parent div
<div className="groups" id={attributeId} onClick={this.viewMore}>
<div className="floatLeft"> Group Name: <h3>My Name</h3></div>
<span className="floatRight typeCd">POC</span>
<div className="clearfix"> Key Attributes:
<ul>
<li> POC 1</li>
</ul>
</div>
</div>
)
};
viewMore = (i,j) => () => {
console.log(i,j)
}
To pass parameters to event handlers we need to use currying.
With the above method no new functions created all the time while render is called.
Since I see these kind of suggestions in multiple places, I am going to move my comment into an answer as well, to provide an additional view:
class TestComponent extends React.Component {
constructor() {
super();
this.onClick = this.handleClick.bind(this);
}
handleClick(event) {
const {id} = event.target;
console.log(id);
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>
{this.props.name}
</h3>
</div>
);
}
}
This allows to:
avoid unnecessary binds
access the id and whatever else properties in a much more React-ive manner.
Of course, the above example assumes that you receive the id as a prop, but you can do the necessary manipulations as well.
UPDATE 1 -- Nov 28, 2016
Added link to CodePen from comments above.
UPDATE 2 -- Mar 30, 2017
As mentioned, this wouldn't work if you use React.createClass to define your components. You don't have a constructor to pull this off. You can use other lifecycle methods, if you don't mind a little ugliness.
Having said that, it is 2017. Use ES6, would you?!
UPDATE 3 -- May 12, 2017
If you are using class properties transform, then you can simplify it further:
class TestComponent extends React.Component {
onClick = (event) => {
const {id} = event.target;
console.log(id);
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>
{this.props.name}
</h3>
</div>
);
}
}
UPDATE 4 -- Feb 4, 2018
Due to improvements of bind and friends in V8 (Chakra and such probably too), you just may be better off using the this.click.bind(this) or wrapping it in an arrow function when passing to onClick.
Why?
The previous method, created for performance reasons only, closed some possibilities for dynamically injecting functions onto the component's prototype.
NOTE 1 -- Apr 14, 2018
Keep in mind that the method mentioned in Update 4 still introduces some performance issues, as on each render pass a new function is created as a result of bind. This, in turn, will trickle down to the child component and cause unnecessary re-renders, as the function changes each time.
The same thing happens when you pass an arrow function inline.
All other methods, like using class properties, will mess with your inheritance (which you should be avoiding, but still), simply due to the fact that, currently, Babel transpiles them to "on-instance" functions, which are not on the prototype chain.
So, this:
class Person {
printA = () => { console.log('a') }
}
becomes:
function _classCallCheck(instance, Constructor) {...abridged...}
var Person = function Person() {
_classCallCheck(this, Person);
this.printA = function () {
console.log('a');
};
};
I've made an updated answer for ES6 here:
https://stackoverflow.com/a/35748912/76840
Essentially, you can use arrow function expressions, which have the benefit of preserving this:
onClick={(event)=>this.viewMore(attributeId, event)}
As of this edit, if you're using Babel with stage-2 enabled, you can use a property like so:
// Within your class...
viewMore = (event) => { /* ... */ }
// Within render method in your JSX
onClick = {this.viewMore}
You can use currying function.
ES5:
viewMore(param) { // param is the argument you passed to the function
return function(e) { // e is the event object that returned
};
}
ES6
viewMore = param => e => {
// param is the argument you passed to the function
// e is the event object that returned
};
And just use it like this:
onClick={this.viewMore("some param")}
Here is an update and an overview of previous answers:
Using onClick={this.viewMore.bind(this, attributeId)} by #HenrikAndersson
.While this approach serves the purpose it uses the bind syntax with which many are not comfortable.
Using public class field mentioned by #ZenMaster.This solution has more or less the same performance, it also comes with a better syntax. But it turns tricky when we have to pass a parameter.
class TestComponent extends React.Component {
onClick = (event) => {
const {id} = event.target;
console.log(id);
}
render() {
return (
<div>
<h3 id={this.props.id} onClick={this.onClick}>
{this.props.name}
</h3>
</div>
);
}
}
The above mentioned approach skips passing parameters and instead uses custom attributes to access the data required in click handler.
A better solution would be :
class MyComponent extends React.Component {
handleClick = (item) => (e) => {
e.preventDefault()
console.log(`This has access to item ${item}! and event(e)`)
}
render(){
const item={ id:'1', value: 'a' }
return(
<button onClick={ this.handleClick(item) } >Click</button>
)
}
}
Reference: Handle events by arrow functions in React app
Here is the code how to use on click event.
var attributeId = "groups_";
attributeId = 32;
const viewMore = (val) => () => {
console.log(val)
}
return (
//parent div
<div className="groups" id={attributeId} onClick={viewMore(attributeId)}>
<div className="floatLeft"> Group Name: <h3>My Name</h3></div>
<span className="floatRight typeCd">POC</span>
<div className="clearfix"> Key Attributes:
<ul>
<li> POC 1</li>
</ul>
</div>
</div>
)

Categories