Arrow functions are an essential part of every React class. However, members
of React classes can be non-arrow, too. Lets take a look at the following React app:
import React, { Component } from 'react'; import './App.css'; class App extends Component { state = { halloworld: 'halloworld' } sayHalloWorld() { alert(this.state.halloworld); } sayHalloWorldArrow = () => { alert(this.state.halloworld); } render() { return ( <div className="App"> <button onClick={this.sayHalloWorld}>Click Me No Bind</button> <button onClick={this.sayHalloWorld.bind(this)}>Click Me With Bind</button> <button onClick={this.sayHalloWorldArrow}>Click Me Arrow</button> </div> ); } } export default App;
This app shows three buttons, each shows an alert box “halloworld” when being clicked. Wait, each of them?
No, the first button, in fact, creates an error which says that this.state.halloworld is undefined.
Why is that?
To understand this, it is essential to understand what happens when React classes are instantiated. Have you ever noticed, that you never ever instantiate any of your React classes? I guess so! The reason is, that the React framework instantiates your classes, not you.
Lets create a “fake” React class and instantiate this by ourselves:
class fakeReactClass { state = { halloworld: 'Hallo World' } sayHalloWorld() { console.log( this.state.halloworld ); } render() { return this.sayHalloWorld; } } // here we act as the React framework and instantiate our React class const frc = new fakeReactClass(); frc.render()(); // this executes the reference to this.sayHalloWorld
Note: You need Babel 7 to transpile this ES2015 to older JavaScript in order to run it.
So, what happens when we run this code? We get an error! TypeError: Cannot read property ‘state’ of undefined.
Why is that? The reason is that the this-Keyword of the function sayHalloWorld looses its reference to class fakeReactClass, when you call sayHalloWorld(). It now points to nowhere, to undefined.
Therefore, it is essantial to explicitly return a reference of sayHalloWorld in which the this-Keyword is forced to point to fakeReactClass:
class fakeReactClass { state = { halloworld: 'Hallo World' } sayHalloWorld() { console.log( this.state.halloworld ); } render() { return this.sayHalloWorld.bind(this); } } // here we act as the React framework and instantiate our React class const frc = new fakeReactClass(); frc.render()(); // this executes the reference to this.sayHalloWorld
In contrast to the first example, here we return a reference to this.sayHalloWorld
that is explicitly bound to the fakeReactClass. This can be done with the bind() function
that is part of every function object in JavaScript.
So what about arrow functions then? Not that only their syntax may appear more handy
to many developers, there is a significant difference to ordinary function: the this-Keyword inside arrow functions sticks to the lexical context no matther
in what context the arrow function will be executed later:
class fakeReactClass { state = { halloworld: 'Hallo World' } sayHalloWorldArrow = () => { console.log( this.state.halloworld ); } render() { return this.sayHalloWorldArrow; } } // here we act as the React framework and instantiate our React class const frc = new fakeReactClass(); frc.render()(); // this executes the reference to this.sayHalloWorldArrow
To sum it up, the arrow function is used as a shorter version for all the bind()
calls that ordinary functions in JavaScript entail.