Why you shouldn't use inline arrow functions in JSX props
Using arrow functions or binding in JSX is a bad practice that hurts performance, because the function is recreated on each render.
- Whenever a function is created, the previous function is garbage collected. Rerendering many elements might create jank in animations. 
- Using an inline arrow function will cause - PureComponents, and components that use- shallowComparein the- shouldComponentUpdatemethod to rerender anyway. Since the arrow function prop is recreated each time, the shallow compare will identify it as a change to a prop, and the component will rerender.
 
As you can see in the following 2 examples - when we use inline arrow function, the <Button> component is rerendered each time (the console shows the 'render button' text).
Example 1 - PureComponent without inline handler
class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}
class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  onClick = () => this.setState((prevState) => ({
    counter: prevState.counter + 1
  }));
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ this.onClick } />
        <div>{ counter }</div>
      </div>
    );
  }
}
ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
 
 
Example 2 - PureComponent with inline handler
class Button extends React.PureComponent {
  render() {
    const { onClick } = this.props;
    
    console.log('render button');
    
    return (
      <button onClick={ onClick }>Click</button>
    );
  }
}
class Parent extends React.Component {
  state = {
    counter: 0
  }
  
  render() {
    const { counter } = this.state;
    
    return (
      <div>
        <Button onClick={ () => this.setState((prevState) => ({
          counter: prevState.counter + 1
        })) } />
        <div>{ counter }</div>
      </div>
    );
  }
}
ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
 
 
Binding methods to this without inlining arrow functions
- Binding the method manually in the constructor: - class Button extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.cb = this.cb.bind(this);
  }
  cb() {
  }
  render() {
    return (
      <button onClick={ this.cb }>Click</button>
    );
  }
}
 
- Binding a method using the proposal-class-fields with an arrow function. As this is  a stage 3 proposal, you'll need to add the Stage 3 preset or the Class properties transform to your babel configuration. - class Button extends React.Component {
  cb = () => { // the class property is initialized with an arrow function that binds this to the class
  }
  render() {
    return (
      <button onClick={ this.cb }>Click</button>
    );
  }
}
 
Function Components with inner callbacks
When we create an inner function (event handler for example) inside a function component, the function will be recreated every time the component is rendered. If the function is passed as props (or via context) to a child component (Button in this case), that child will re-render as well.
Example 1 - Function Component with an inner callback:
const { memo, useState } = React;
const Button = memo(({ onClick }) => console.log('render button') || (
  <button onClick={onClick}>Click</button>
));
const Parent = () => {
  const [counter, setCounter] = useState(0);
  
  const increment = () => setCounter(counter => counter + 1); // the function is recreated all the time
  
  return (
    <div>
      <Button onClick={increment} />
      
      <div>{counter}</div>
    </div>
  );
}
ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
 
 
To solve this problem, we can wrap the callback with the useCallback() hook, and set the dependencies to an empty array.
Note: the useState generated function accepts an updater function, that provides the current state. In this way, we don't need to set the current state a dependency of useCallback.
Example 2 - Function Component with an inner callback wrapped with useCallback:
const { memo, useState, useCallback } = React;
const Button = memo(({ onClick }) => console.log('render button') || (
  <button onClick={onClick}>Click</button>
));
const Parent = () => {
  const [counter, setCounter] = useState(0);
  
  const increment = useCallback(() => setCounter(counter => counter + 1), []);
  
  return (
    <div>
      <Button onClick={increment} />
      
      <div>{counter}</div>
    </div>
  );
}
ReactDOM.render(
  <Parent />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>