React ES6 Arrow Functions

Arrow functions offer shorter syntax and, crucially, lexically bind 'this' — which is why React code leans on them so heavily.

Arrow function syntax

Arrow functions, introduced in ES6, provide a compact alternative to the 'function' keyword. Parentheses around a single parameter are optional, a single expression body is returned implicitly without the 'return' keyword, and a block body with braces behaves like a normal function body.

Arrow function variations

function App() {
  // Traditional function
  function double(n) {
    return n * 2;
  }

  // Arrow function, block body
  const doubleArrow = (n) => {
    return n * 2;
  };

  // Arrow function, implicit return
  const doubleShort = (n) => n * 2;

  // Single parameter, parens optional
  const square = n => n * n;

  // No parameters
  const getRandom = () => Math.random();

  // Returning an object literal needs parentheses
  const makePoint = (x, y) => ({ x, y });

  console.log(
    double(4),
    doubleArrow(4),
    doubleShort(4),
    square(4),
    getRandom(),
    makePoint(1, 2)
  );

  return (
    <div>
      <p>double(4) = {double(4)}</p>
      <p>doubleArrow(4) = {doubleArrow(4)}</p>
      <p>doubleShort(4) = {doubleShort(4)}</p>
      <p>square(4) = {square(4)}</p>
      <p>makePoint(1, 2) = {JSON.stringify(makePoint(1, 2))}</p>
    </div>
  );
}

export default App;

Lexical 'this': the real reason React uses them

A regular function creates its own 'this' binding depending on how it's called, which is what causes event handlers in class components to lose track of their instance. An arrow function has no 'this' of its own — it captures 'this' from the surrounding scope where it was defined, and that binding never changes no matter how the arrow function is later invoked.

Why arrow functions fix 'this' in classes

import React from 'react';

class Timer extends React.Component {
  state = { seconds: 0 };

  // Arrow function class field: `this` is captured from Timer's instance
  tick = () => {
    this.setState((prev) => ({ seconds: prev.seconds + 1 }));
  };

  componentDidMount() {
    this.intervalId = setInterval(this.tick, 1000);
  }

  componentWillUnmount() {
    clearInterval(this.intervalId);
  }

  render() {
    return <p>Seconds elapsed: {this.state.seconds}</p>;
  }
}

export default Timer;

If 'tick' were written with the 'function' keyword instead, calling it via setInterval would invoke it with 'this' set to undefined (in strict mode) rather than the Timer instance, and 'this.setState' would throw.

Arrow functions in function components

Function components don't have a 'this' problem since Hooks replaced classes, but arrow functions are still everywhere in modern React — for inline event handlers, for callbacks passed to array methods like .map(), and for the component definitions themselves.

Arrow functions in everyday React code

function ProductList({ products, onSelect }) {
  return (
    <ul>
      {products.map((product) => (
        <li key={product.id} onClick={() => onSelect(product.id)}>
          {product.name}
        </li>
      ))}
    </ul>
  );
}

function App() {
  const products = [
    { id: 1, name: 'Keyboard' },
    { id: 2, name: 'Mouse' },
    { id: 3, name: 'Monitor' },
  ];

  function handleSelect(id) {
    console.log('Selected product', id);
  }

  return <ProductList products={products} onSelect={handleSelect} />;
}

export default App;
  • Arrow functions cannot be used as constructors — `new MyArrow()` throws a TypeError.
  • Arrow functions have no 'arguments' object; use rest parameters (...args) instead.
  • Arrow functions cannot be generator functions (no `function*` equivalent).
  • Arrow functions do not have their own 'this', 'super', or 'new.target' bindings.
Featurefunction expressionArrow function
Own 'this' bindingYes, depends on call siteNo, inherited lexically
Can be used with 'new'YesNo
'arguments' objectYesNo
Implicit returnNoYes, for expression bodies
Note: Defining an arrow function inline inside render/JSX (like onClick={() => onSelect(id)}) creates a brand-new function on every render. For most UI this is harmless, but if the child is wrapped in React.memo, that new function reference will defeat the memoization unless you stabilize it with useCallback.
Note: Because arrow functions capture 'this' lexically, defining one directly on an object literal's method does NOT give you the object as 'this' — it captures 'this' from whatever scope contains the object literal, which is rarely what you want for object methods.

Exercise: React ES6 Arrow Functions

What value of `this` does an arrow function use inside a class method?