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
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.
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.
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.
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.
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:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With