How to avoid bind or inline arrow functions inside render method

Asked
Active3 hr before
Viewed126 times

10 Answers

arrowmethodinlineavoid
90%

First: A simple solution will be to create a component for the content inside a map function and pass the values as props and when you call the function from the child component you can pass the value to the function passed down as props. ,P.S. However this is not a best solution and will still result in multiple functions being created but is still an improvement over the initial case.,Generally speaking, yes, it is OK, and it is often the easiest way to pass parameters to callback functions.

Parent

deleteTodo = (val) => {
    console.log(val)
}
todos.map(el => 
    <MyComponent val={el} onClick={this.deleteTodo}/> 

)

MyComponent

class MyComponent extends React.Component {
    deleteTodo = () => {
        this.props.onClick(this.props.val);
    }
    render() {
       return <div  onClick={this.deleteTodo}> {this.props.val} </div>
    }
}
class Parent extends React.Component {
     _deleteTodo = (val) => {
        console.log(val)
    }
    render() {
        var todos = ['a', 'b', 'c'];
        return (
           <div>{todos.map(el => 
             <MyComponent key={el} val={el} onClick={this._deleteTodo}/> 
        
           )}</div>
        )
    }
    
   
}

class MyComponent extends React.Component {
        _deleteTodo = () => {
                     console.log('here');   this.props.onClick(this.props.val);
        }
        render() {
           return <div onClick={this._deleteTodo}> {this.props.val} </div>
        }
    }
    
ReactDOM.render(<Parent/>, document.getElementById('app'));
<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="app"></div>

Second: The other approach to it would be to use memoize and return a function

constructor() {
   super();
   this._deleteTodoListener = _.memoize(
      this._deleteTodo, (element) => {
         return element.hashCode();
      }
   )
}

_deleteTodo = (element) => {
   //delete handling here
}

and using it like

todos.map(el => <div key={el} onClick={this._deleteTodoListener(el)}> {el} </div>)

Third: However a more appropriate solution to this will be to add an attribute to the topmost div and get the value from event like

_deleteTodo = (e) => {
     console.log(e.currentTarget.getAttribute('data-value'));

 }

 todos.map(el => <div key={el} data-value={el} onClick={this._deleteTodo}> {el} </div>)
load more v
88%

In a previous post, I explained how to extract React child components to avoid using bind or arrow functions in render. But I didn’t provide a clear demo to show why this is useful.,I’ve authored multiple React and JavaScript courses on Pluralsight (free trial). My latest, “Creating Reusable React Components” just published! ?,How? Extract child components, or pass data on the HTML element.

Pretag
 Pretag team - issue, fix, solve, resolve
72%

First: A simple solution will be to create a component for the content inside a map function and pass the values as props and when you call the function from the child component you can pass the value to the function passed down as props. ,P.S. However this is not a best solution and will still result in multiple functions being created but is still an improvement over the initial case.,Even if the props are exactly the same, the following code will still re-render children unless they prevent it in their own shouldComponentUpdate (they might inherit it from PureComponent):

Parent

deleteTodo = (val) => {
    console.log(val)
}
todos.map(el => 
    <MyComponent val={el} onClick={this.deleteTodo}/> 

)

MyComponent

class MyComponent extends React.Component {
    deleteTodo = () => {
        this.props.onClick(this.props.val);
    }
    render() {
       return <div  onClick={this.deleteTodo}> {this.props.val} </div>
    }
}
class Parent extends React.Component {
     _deleteTodo = (val) => {
        console.log(val)
    }
    render() {
        var todos = ['a', 'b', 'c'];
        return (
           <div>{todos.map(el => 
             <MyComponent key={el} val={el} onClick={this._deleteTodo}/> 
        
           )}</div>
        )
    }
    
   
}

class MyComponent extends React.Component {
        _deleteTodo = () => {
                     console.log('here');   this.props.onClick(this.props.val);
        }
        render() {
           return <div onClick={this._deleteTodo}> {this.props.val} </div>
        }
    }
    
ReactDOM.render(<Parent/>, document.getElementById('app'));
<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="app"></div>

Second: The other approach to it would be to use memoize and return a function

constructor() {
   super();
   this._deleteTodoListener = _.memoize(
      this._deleteTodo, (element) => {
         return element.hashCode();
      }
   )
}

_deleteTodo = (element) => {
   //delete handling here
}

and using it like

todos.map(el => <div key={el} onClick={this._deleteTodoListener(el)}> {el} </div>)

Third: However a more appropriate solution to this will be to add an attribute to the topmost div and get the value from event like

_deleteTodo = (e) => {
     console.log(e.currentTarget.getAttribute('data-value'));

 }

 todos.map(el => <div key={el} data-value={el} onClick={this._deleteTodo}> {el} </div>)

Example

import React, { Component, PureComponent } from 'react';
import { render } from 'react-dom';

class Product extends PureComponent {
  render() {
    const { id, name, onDelete } = this.props;

    console.log(`<Product id=${id} /> render()`);
    return (
      <li>
        {id} - {name}
        <button onClick={() => onDelete(id)}>Delete</button>
      </li>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      products: [
        { id: 1, name: 'Foo' },
        { id: 2, name: 'Bar' },
      ],
    };

    this.handleDelete = this.handleDelete.bind(this);
  }

  handleDelete(productId) {
    this.setState(prevState => ({
      products: prevState.products.filter(product => product.id !== productId),
    }));
  }

  render() {
    console.log(`<App /> render()`);
    return (
      <div>
        <h1>Products</h1>
        <ul>
          {
            this.state.products.map(product => (
              <Product 
                key={product.id}
                onDelete={this.handleDelete}
                {...product}
              />
            ))
          }
        </ul>
      </div>
    ); 
  }
}

render(<App />, document.getElementById('root'));

Even if the props are exactly the same, the following code will still re-render children unless they prevent it in their own shouldComponentUpdate (they might inherit it from PureComponent):

handleChildClick = itemId => {}

render() {
   return this.props.array.map(itemData => < Child onClick = {
         this.handleChildClick
      }
      data = {
         itemData
      })
}

So, in order to avoid re-renders, the child component has to implement shouldComponentUpdate anyway. Now, the only reasonable implementation is completely ignoring onClick regardless of whether it has changed:

shouldComponentUpdate(nextProps) {
   return this.props.array !== nextProps.array;
}
load more v
65%

We should avoid method binding inside render because during re-rendering it will create the new methods instead of using the old one, that will affect the performance.,How to avoid this way of binding inside render method or what are the alternatives of this?,How to avoid this way of binding inside render method or what are the alternatives of this?

So for the scenarios like this:

<input onChange = { this._handleChange.bind(this) } ...../>

We can bind _handleChange method either in constructor:

this._handleChange = this._handleChange.bind(this);
_handleChange = () => {
   ....
}

Now lets consider the case where we want to pass some extra parameter, lets say in a simple todo app, onclick of item i need to delete the item from array, for that i need to pass either the item index or the todo name in each onClick method:

todos.map(el => <div key={el} onClick={this._deleteTodo.bind(this, el)}> {el} </div>)
load more v
75%

How to avoid binding by using arrow functions in callbacks in ReactJS?,Writing code in comment? Please use ide.geeksforgeeks.org, generate link and share the link here.,How to bind ‘this’ keyword to resolve classical error message ‘state of undefined’ in React?

40%

Use arrow functions within render. It’s ok. I promise.,In an arrow function, this means the same thing within the function body as it does outside of it. Which means that if you use arrow functions within your component’s render or lifecycle methods, they can use this and this.setState with no surprises.,If performance is important for your component, you’ll want to define any arrow functions just once. And the obvious time to do this is when the component loads.

import React from 'react'
import ReactDOM from 'react-dom'

class BrokenButton extends React.Component {
  render() {
    return (
      <button onClick={this.handleClick} style={this.state}>
        Set background to red
      </button>
    )
  }

  handleClick() {
    this.setState({ backgroundColor: 'red' })
  }
}

ReactDOM.render(
  <BrokenButton />,
  document.getElementById('root')
)
load more v
22%

Simply put, an inline function is a function that is defined and passed down inside the render method of a React component.,We'd then have to define 3 custom event handlers in the class definition and bind context to all three functions in the constructor.,The onClick prop, in the example above, is being passed as an inline function that calls this.setState. The function is defined within the render method, often inline with JSX. In the context of React applications, this is a very popular and widely used pattern.

Pretag
 Pretag team - issue, fix, solve, resolve
60%

Avoid generating new references in render method if you really need the PureComponent optimization to work.,This topic is already well discussed and the intent of this article is to share how I prefer to use arrow functions in React and my view on PureComponent optimizations.,If the component you pass this generated function to is extending PureComponent, it will not be able to bail out on rerendering, even if the actual data has not changed.

Pretag
 Pretag team - issue, fix, solve, resolve
48%

Just like arrow functions, function binding and the render method are not friends.,This render method looks innocent but really it is quite the opposite. Just like before when we used an arrow function, this is going to always re-render.,Bind isn’t all that bad, just in the render method. So lets take the example from above and fix it. We will still use bind but in a more efficient way.

We all love them, but should be cautious when using them with React. Arrow functions are great, they let us quickly create new javascript function short hand. The consequence of this is exactly that, it creates a new function every time it is executed. For the most part in Javascript this isn’t a real issue. When it comes to the React render method this can quickly become an issue.

render(){ return (  <View>   <TouchableOpacity onPress={() => console.log('Hello!')}>     Click Me   </TouchableOpacity>  </View> )}
load more v
23%

Note that this behavior is different for ref props, which is a special case in React that does not cause re-renders when a brand new function is passed. See ignore-refs below for more information.,Refs are a special-case that do not behave like other props. Sending a new function in on ever render will not cause re-renders like it could with any other prop.,A common use case of bind in render is when rendering a list, to have a separate callback per list item:

<Foo onClick={this._handleClick.bind(this)}></Foo>
load more v

Other "arrow-method" queries related to "How to avoid bind or inline arrow functions inside render method"