I understand that arrow functions make things more efficient by not recreating the functions each render similar to how binding in the constructor works.
This is not true. It depends on where exactly are you using the Arrow function. If Arrow function are used in render method, then they create a new instance everytime render is called just like how bind would work. Consider this example
<div onClick={()=>{this.onClick()}}>Previous</div>
Here each time render is called an anonymous function is created and that function when called, calls this.onClick.
However consider the case below
onClick = () => {
console.log("Div is clicked")
}
In above case, the arrow function does not recreate function everytime, but binds the context to the React component as An arrow function does not have its own this; the this value of the enclosing execution context is used. once when the class is instantiated. This is similar to how binding works is constructor. This is a part of proposed class fields for arrow functions and it isn't a ES6 feature,
To understand what you wish to ask, you must know that a function gets its context from where it is called. Check this question for more understanding.
In your case, you have used Arrow function to define prevItem and hence it gets the context of the enclosing React component.
prevItem = () => {
console.log("Div is clicked")
}
render(){
return (
<SecondClass prevItem={this.prevItem} />
)
}
Now in its child, even if you call prevItem with any custom context, using bind or arrow function, prevItem when executed in parent i.e Main.js will get the context of its enclosing React component. And since you just wish to execute prevItem function and do not want to pass any data to this from the child, writing
<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />
and
<div onClick={()=>{this.props.onClick()}}>Previous</div>
is simply useless and will only add to performance implication since new functions are created in SecondClass and ThirdClass everytime. You simply don't need to have these functions defined as arrow function and could just write
<ThirdClass type="prev" onClick={this.props.prevItem} />
and
<div onClick={this.props.onClick}>Previous</div>
since its already binded in the parent.
Now even if you have to pass some additional data to these function from ThirdClass and SecondClass, you shouldn't directly use Arrow function or bind in render. Have a look at this answer on How to Avoid binding in Render method
I understand that arrow functions make things more efficient by not recreating the functions each render similar to how binding in the constructor works.
This is not true. It depends on where exactly are you using the Arrow function. If Arrow function are used in render method, then they create a new instance everytime render is called just like how bind would work. Consider this example
<div onClick={()=>{this.onClick()}}>Previous</div>
Here each time render is called an anonymous function is created and that function when called, calls this.onClick.
However consider the case below
onClick = () => {
console.log("Div is clicked")
}
In above case, the arrow function does not recreate function everytime, but binds the context to the React component as An arrow function does not have its own this; the this value of the enclosing execution context is used. once when the class is instantiated. This is similar to how binding works is constructor. This is a part of proposed class fields for arrow functions and it isn't a ES6 feature,
To understand what you wish to ask, you must know that a function gets its context from where it is called. Check this question for more understanding.
In your case, you have used Arrow function to define prevItem and hence it gets the context of the enclosing React component.
prevItem = () => {
console.log("Div is clicked")
}
render(){
return (
<SecondClass prevItem={this.prevItem} />
)
}
Now in its child, even if you call prevItem with any custom context, using bind or arrow function, prevItem when executed in parent i.e Main.js will get the context of its enclosing React component. And since you just wish to execute prevItem function and do not want to pass any data to this from the child, writing
<ThirdClass type="prev" onClick={()=>this.props.prevItem()} />
and
<div onClick={()=>{this.props.onClick()}}>Previous</div>
is simply useless and will only add to performance implication since new functions are created in SecondClass and ThirdClass everytime. You simply don't need to have these functions defined as arrow function and could just write
<ThirdClass type="prev" onClick={this.props.prevItem} />
and
<div onClick={this.props.onClick}>Previous</div>
since its already binded in the parent.
Now even if you have to pass some additional data to these function from ThirdClass and SecondClass, you shouldn't directly use Arrow function or bind in render. Have a look at this answer on How to Avoid binding in Render method
I understand that arrow functions make things more efficient by not recreating the functions each time they are referred to
This is not true.
Arrow functions handles the this context in a lexical way, where "normal" function do it dynamically. I wrote about the this key word in depth if you need more info about it.
On both of your examples of the inline arrow function, you are creating a new function instance on each render.
This will create and pass a new instance on each render
onClick={() => {}}
On the 3rd example you only have one instance.
This only pass a reference to an already existing instance
onClick={this.myHandler}
As for the benefits of arrow functions as class fields (there is a small down side, i will post it in the bottom of the answer), if you have a normal function handler that needs to access the current instance of the
class via this:
myHandler(){
// this.setState(...)
}
You will need to explicit bind it to the class.
The most common approach will be to do it in the constructor because it runs only once:
constructor(props){
super(props);
this.myHandler = this.myHandler.bind(this);
}
If you use an arrow function as the handler though, you don't need to bind it to the class because as mentioned above, the arrow function use a lexical context for this:
myHandler = () => {
// this.setState(...)
}
With both approaches you will use the handler like this:
<div onClick={this.myHandler}></div>
The main reason for taking this approach:
<div onClick={() => this.myHandler(someParameter)}></div>
Is if you want to pass parameters to the handler beside the native event that get passed, meaning you want to pass a parameter upwards.
As mentioned, this will create a new function instance on each render.
(There is a better approach for this, keep reading).
Running example for such use case:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [{ name: 'item 1', active: false }, { name: 'item 2', active: true }],
}
}
toggleITem = (itemName) => {
this.setState(prev => {
const nextState = prev.items.map(item => {
if (item.name !== itemName) return item;
return {
...item,
active: !item.active
}
});
return { items: nextState };
});
}
render() {
const { items } = this.state;
return (
<div>
{
items.map(item => {
const style = { color: item.active ? 'green' : 'red' };
return (
<div
onClick={() => this.toggleITem(item.name)}
style={style}
>
{item.name}
</div>
)})
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
A better approach would be to create component composition.
You can create a child component that wraps the relevant markup, will have it's own handler and will get both the data and handler as props from the parent.
The child component will then invoke the handler that it got from the parent and will pass the data as a parameter.
Running example with child component:
class Item extends React.Component {
onClick = () => {
const { onClick, name } = this.props;
onClick(name);
}
render() {
const { name, active } = this.props;
const style = { color: active ? 'green' : 'red' };
return (<div style={style} onClick={this.onClick}>{name}</div>)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [{ name: 'item 1', active: false }, { name: 'item 2', active: true }],
}
}
toggleITem = (itemName) => {
this.setState(prev => {
const nextState = prev.items.map(item => {
if (item.name !== itemName) return item;
return {
...item,
active: !item.active
}
});
return { items: nextState };
});
}
render() {
const { items } = this.state;
return (
<div>
{
items.map(item => {
return <Item {...item} onClick={this.toggleITem} />
})
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Class Fields the down-side:
As i mentioned, there is a small down-side for class fields.
The difference between a class method and a class field is that the class field is attached to the instance of the class (constructor function).
where as the class methods and objects are attached to the prototype.
Hence, if you will have ridiculously large amount of instances of this class you may get a performance hit.
Given this code block:
class MyClass {
myMethod(){}
myOtherMethod = () => {}
}
babel will transpile it to this:
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var MyClass = function() {
function MyClass() {
_classCallCheck(this, MyClass);
this.myOtherMethod = function() {};
}
_createClass(MyClass, [{
key: "myMethod",
value: function myMethod() {}
}]);
return MyClass;
}();
Why is arrow syntax preferred over function declaration for functional React components?
React - Can I define an arrow function inside Class Component
Arrows, function, or ???
Is it necessary to use arrow function everywhere??
Videos
I would say that this is a bit opinionated choice really. There are at least several reasons why I (personally) see arrow function use for a purely functional component as pretty bad practice. Here are those:
Syntax abuse. When we define function component we don't need to pre-bind its context to a specific scope. The context (
this) is going to beundefinedanyway in the module namespace. The use of arrow functions is dictated here by pure aesthetics reasons like conciseness. But arrow functions as language feature has a very specific purpose for existence in the first place, and this is not coolness and conciseness.Error stack trace. Exceptions thrown in arrow function will be less descriptive because arrow function is anonymous by definition. This is not the huge problem probably since React project will most likely be configured with proper source maps support, but still stack trace will be a bit more clear if named function is used. As noted in comments this is not really an issue of the functional component, as the name will be the name of the variable basically.
Less convenient logging. Consider this very typical pure function component style:
const Header = ({ name, branding }) => ( <header> ... </header> )In the function above it's impossible to throw in quick
debuggerstatement orconsole.log. You will have to temporarily convert it to something like thisconst Header = function ({ name, branding }) { console.log(name) return ( <header> ... </header> ) }This might be pretty annoying especially for bigger pure functional components.
That being said this is a very popular choice for many teams, also by default preferred by ESLint, so if you don't see the problem with it, then it is probably okay.
Actually, there is no difference between them, I made a little project on the CodeSandBox and made two simple components, one of them is the Arrow component by using the arrow function:
import React from 'react';
const MyArrowComponent = () => (
<main>
<h2>Arrow</h2>
</main>
);
export default MyArrowComponent;
And the other is the Declaration component by using function declaration:
import React from "react";
function MyFunctionComponent() {
return (
<main>
<h2>Declaration</h2>
</main>
);
}
export default MyFunctionComponent;
Then I ran the yarn build command and got the bundle like the one below:
(window.webpackJsonp = window.webpackJsonp || []).push([[0], {
14: function (e, n, t) {
"use strict";
t.r(n);
var a = t(0), r = t.n(a), l = t(2),
c = t.n(l), u = t(3), i = t(4), o = t(6), m = t(5), E = t(7);
var p = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Declaration"))
}, s = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Arrow"))
}, d = function (e) {
function n() {
return (
Object(u.a)(this, n),
Object(o.a)(this, Object(m.a)(n).apply(this, arguments))
}
return Object(E.a)(n, e), Object(i.a)(n, [{
key: "render", value: function () {
return r.a.createElement(
'div',
null,
r.a.createElement('div', null, 'Hi'),
r.a.createElement(p, null),
r.a.createElement(s, null)
);
}
}]), n
}(r.a.Component);
c.a.render(r.a.createElement(d, null), document.getElementById("root"))
}, 8: function (e, n, t) {
e.exports = t(14)
}
}, [[8, 1, 2]]]);
Pay attention to the definition of the Arrow and the Declaration component:
var p = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Declaration"))
}, s = function () {
return r.a.createElement("main", null, r.a.createElement("h2", null, "Arrow"))
}
Both of them are defined in the same way, so there is no difference between them and it is fully opinion based on developers' attitude to code readability and clean code, based on ESLint 5.x in our team, we chose the arrow function to define the functional components.