Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Closures in React

Is it ok use closures in react, for event handlers? For example, i have some function and a lot of menu in navigation and in navigation component i use something like this:

handleMenuClick(path) {
  return () => router.goTo(path)
}
... 
<MenuItem
  handleTouchTap={this.handleMenuClick('/home')}
>

or i should prefer just arrow function?

<MenuItem
  handleTouchTap={() => router.goTo('/home')}
>

first variant really make code cleaner, but i'm worried about performance with a large number of such elements

like image 717
vanless Avatar asked Jul 11 '17 18:07

vanless


People also ask

What are closures used for?

Closures are useful because they let you associate data (the lexical environment) with a function that operates on that data. This has obvious parallels to object-oriented programming, where objects allow you to associate data (the object's properties) with one or more methods.

Are React hooks closures?

React hooks have made it very easy to manage state and side effects in functional components. They let us use state and other React features without writing a class. Hooks rely on JavaScript closures. If you are not aware of JavaScript closures, I would recommend watching this video to learn about it.

What is closure and types?

Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms: Global functions are closures that have a name and don't capture any values. Nested functions are closures that have a name and can capture values from their enclosing function.

What is closure and callback?

Callback - a callback is executable code that is passed as an argument to other code. Closure - a closure is a function that is evaluated in an environment containing one or more bound variables. When called, the function can access these variables.


1 Answers

Both should be avoided.

While they'll both work, they both have the same weakness that they'll cause unnecessary renders because the function is being created dynamically, and will thus present as a different object.

Instead of either of those, you want to create your functions in a static way and then pass them in. For something like your MenuItem, it should just get the string for the path and then have the code to do the routing inside. If it needs the router, you should pass that in instead.

The function should then be a pre-bind-ed function (usually in the constructor) and just passed in.

export class MenuItem extends React.Component {
    constructor() {
      this.handleClick = () => this.props.router.go(this.props.path);
    }

    render() {
      return (
        <Button onClick={ this.handleClick }>Go to link</Button>
      );
    }
}

You can use an arrow function in the constructor. That way it isn't recreated every render function, and thus you avoid unnecessary renders. That pattern works well for single-line simple functions. For more complex functions, you can also create them as a separate function, then bind it in the constructor.

export class MenuItem extends React.Component {
  handleClick() {
    this.props.router.go(this.props.path);
  }

  constructor() {
    this.handleClick = this.handleClick.bind(this);
  }

  render() { /* same as above */ }
}

The point of this is that the handler is the same function every time. If it was different (which both methods you describe above would be), then React would do unnecessary re-renders of the object because it would be a different function every time.

Here are two articles which go into more details:

  • https://ryanfunduk.com/articles/never-bind-in-render/
  • https://daveceddia.com/avoid-bind-when-passing-props/
like image 72
samanime Avatar answered Oct 14 '22 00:10

samanime