Using .bind() in functional React component, is it recommended? - javascript

I saw this syntax below during our code review, it's my first time seeing it, I couldn't find any article online of it being used/recommended - usually I would opt for arrow function or useCallback in this use case. Just curious if anyone else here used this, and if yes, would you be able to provide some references or an article saying it's safe or recommended to use it.
function DummyComponent({ onBtnClick }) {
const [data, setData] = useState('some-data-that-only-exists-here');
return (
<div>
<button onClick={onBtnClick.bind(null, dummyData)} />
</div>
)
}
I was told that this prevents the function from being recreated on rerenders. Also, during writing of tests, it passes a class which seems to be the class of the HTML button as the 2nd argument when onBtnClick is triggered which is one of the reason why I didn't approve of this and needed some references.

While it's technically possible, the use of .bind or .call or .apply instead of an anonymous function is usually done to change the this inside the function. Here, you don't care about this, so it'd probably make a bit more intuitive sense to read and write if you used an anonymous function instead.
<button onClick={() => onBtnClick(dummyData)} />
Or make a higher-order function outside, before returning the JSX:
const makeOnBtnClick = arg => () => onBtnClick(arg);
<button onClick={makeOnBtnClick(dummyData)} />
I was told that this prevents the function from being recreated on rerenders.
No, a new function is created every time the render part (with the .bind runs), so a new function gets attached as the click handler every time. If this is something you're really worried about (which you probably shouldn't be), useCallback would be one way to have a more persistent function that doesn't have to be removed/recreated when rendering - just like you mentioned.

Related

React: Optimization callbacks with or without useCallback

TL;DR
Some blogs say that you don't need to use the useCallback hook every time you pass a callback to child component, and sometimes it is better to create a new function every time. Because the cost of useCallback sometimes higher than the actual performance issue. While React warns that it may lead to performance issues and we need to try to avoid it.
Who is right and what is the way to balance between these two opposing claims?
The full question
I've been reading a lot of blogs and tutorials about react hooks recently, specially about useCallback and useMemo.
Before React 16 (and all its hooks) when I use Class Components, I've always used "constructor binding" for my callbacks, because arrow function or "Bind in render" like those:
render() {
return <button onClick={this.handleClick.bind(this)}>Click Me</button>;
}
render() {
return <button onClick={() => this.handleClick()}>Click Me</button>;
}
Were considered as "bad practice". From React Docs:
Using Function.prototype.bind in render creates a new function each time the component renders, which may have performance implications (see below).
Using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.
So, my rule of thumb was not to pass new functions to props.
In React 16 the useCallback hook tries to helps us to do exactly that thing. But I see a lot of blogs like that or that claim that you don't need to use the useCallback hook every time because the cost of useCallback sometimes higher than the actual issue, and using arrow functions that create a new function on every render is fine.
Both opposing claims made me think that the best option should be something like (if the dependencies array is empty):
function handleCallback() { ... } // Or arrow function...
function Foo(props) {
return <button onClick={handleCallback}>Click Me</button>
}
Because this way doesn't use the "expensive" useCallback and doesn't generating a new function every time. But, actually, this code is not looking so good when you have several callbacks.
So, what is the right balance between these two opposing claims? If creating a new function every time sometimes better than using useCallback, why React has a warning in their docs about it?
(Same question about the "double curly braces" rule of thumb and useMemo/useRef hooks)

Why does React's onClick function require unique syntax? compared to other event triggers?

I have begun to notice an unusual pattern. Any onClick event requires the syntax to be
onClick={() => «name of function»}.
I have also spent time researching as to the reason why onClick seems to be the only event handler which requires the paranthesis, but all I can find are articles that explain what to do but not why it works that way. OnChange and other events do not require that same syntax, but they are all types of events. All advice and explanations are welcome.
onClick doesn't require "the parenthesis". That's an arrow function, it's one of several ways of passing an event handler to the component.
This is one way:
onClick={this.nameOfFunction} // In this case, you need to bind the this in the constructor.
This is another way:
onClick={this.nameOfFunction.bind(this)}
And this is another one:
onClick={() => this.nameOfFunction()}
But, as the docs says: "Using an arrow function in render creates a new function each time the component renders, which may have performance implications (see below)."
Usually, when it comes to React components, the functions probably are using the this.setState method or even accessing to the component props (eg: this.props), so the methods need to use the right this keyword (which is dynamically bound).
The arrow functions are great for this purpose, they provide a nice syntax and also a they don't have its own this, which means that the this that are used inside them are the same as the parent this.
So when you need to pass an event handler to a component without changing the meaning of the this keyword you can do the following:
Defining your event handler as an arrow function
eventHandler = () => console.log(this.props)
...
onClick={this.eventHandler}
Wrapping your event handler with an arrow function
onClick={() => this.eventHandler()}
Using the Function.prototype.bind method
onClick={this.eventHandler.bind(this)}
Note: Is important to mention that if you want to pass an eventHandler to onClick, it should be a reference, otherwise your event handler will be executed everytime the component is rendered.

Calling a method vs using a function to call a method

Suppose we have a method inside a class like this
class Blog extends Component {
postClicked = (id) => {
this.setState({selectedPostId: id})
}
render () {
const newPosts = this.state.posts.map(el => {
return <Post key={el.id}
title={el.title}
author={el.author}
onClick={this.postClicked(el.id)}/>
})
return
//something
{post}
}
}
}
Now, What is the difference between calling the handler like this
onClick={this.postClicked(el.id)} and onClick={() => this.postClicked(el.id)}
Would appreciate if someone can tell me the difference in general
after Ecmascript 6 javascript was introduced with is arrow function link
here ()==>{//code} is a similar as a function() or anonymous function
tell me if you find out what you want
The first option, "this.postClicked(el.id)", will actually call the method, "this.postClicked", with the "el.id" argument, each time the component renders (probably not what's intended).
The second option, "() => this.postClicked(el.id)", will only call the method, "this.postClicked", with the "el.id" argument, when "Post" is clicked.
Overall, if you can find a way to put the "el.id" argument into an "id" or "name" prop on the component
<Post id={el.id} />
then you can do:
<Post
id={el.id}
onClick={this.postClicked}
/>
this.postClicked = (event) => {
const { id } = event.target;
...
}
This last option avoids the use of an unnamed function. If you use an unnamed function, it will cause unnecessary re-renders. React cannot tell that an unnamed function is the same when it's checking whether or not it should re-render, by considering if the props of a component have changed. It considers the unnamed functions to be a new prop each time it checks, causing an unnecessary re-render each time.
Overall, it won't break your app, but it slows down performance slightly if you do it enough. It comes up especially if you start using React Motion (you'll really notice a difference there). It's best to avoid unnamed functions if possible.
you can read this blog it wil clear the things https://medium.com/#machnicki/handle-events-in-react-with-arrow-functions-ede88184bbb
Differences are,
First method is a wrong implementation and it wont give the intended result, where as second one will work.
In the first method you are making a function call, in second one you are assigning a function's signature to onClick.
It is like the combination of below two statements.
var variableName = function(){//some content};
onClick={variableName}
It looks like you question has already been answered. Just a side note though: remember that when assigning your method with an arrow function
onClick={ () => this.method() }
a new anonymous function is created on every re-render. So if the method doesn't need any arguments, it's better to reference the method directly (without parentheses so it's not invoked).
onClick={ this.method }
The first will call the function every time render is done.
The second will do what you want - call it onClick.

react-native - calling functions as arguments

I've got a sneaking suspicion this question might be more todo with JavaScript and/or specifically ES6 than React-Native but I'll try. I have got the following component:
export default class Body extends Component {
componentWillMount() {
this.refresh();
}
clickme() {
console.log('I have been pressed!!!!!');
}
refresh() {
this.props.populateGrid();
}
render() {
return (
<View style={styles.body}>
<Grid inGrid={this.props.grid} />
<Button
onPress={this.clickme}
title={'PressMe'}
/>
</View>
);
}
}
First, I passed 'this.clickme()' to onPress. It didn't work. It was only after removing the braces it started working. Why? Don't we usually call a function including the ()? Also sometimes, you have to pass it in the following format something={() => this.clickme()}. Why/When?
So when do we call function as:
1. {this.clickme}
2. {this.clickme()}
3. {() => this.clickme()}
Thank you.
Short answer:
1 and 3 as you define in your question are effectively the same for Button.onPress -- they are passing in references to function bodies. However, #3 is also defining a new function inline, though it is defined in a very lightweight way. #2 is attempting to call the function inline. You might want to do this (#2) in some cases where you need to pass a number or boolean or string value to a property rather than a callback function as Button.onPress requires.
Longer answer:
The syntax required is defined by the signature of the method you're passing data to on the react component. In this case, we're talking about Button.onPress, which has the signature () => {} -- which means it takes in a callback function and won't pass any arguments to it when called. You don't want to call the function immediately, since the user is not clicking when you define the component. They are clicking some random time later.
Since you need to pass in a function and not its result, you don't want to include the () at the end of the function name. The parentheses will cause the function to be run immediately, whereas the name alone will simply pass a reference to the function body. That reference will be later called by Button.onPress to handle the user interaction.
A lot of JavaScript (and React) is written with a pattern of passing around function references and later calling those functions from within other functions. If you're not familiar with that pattern, definitely spend some time reading about callback patterns.
() => {} is also a shorthand way to define an inline anonymous function. It's called an arrow function, and it can have some performance gains over defining separate function bodies.
More info here:
() => {} (arrow function) documentation on MDN
Callback documentation on MDN

How unperformant are anonymous functions in React component attributes?

You're not supposed to use anonymous functions in react attributes, e.g.
<a onClick=()=>doIt('myId')>Aaron</a>
I understand why this creates a performance problem for React's reconciliation because that anonymous function is recreated on every render pass and will thus always trigger a real DOM re-render of some kind. My question is, for a small component (i.e. not table where every row has a link) is this insignificant? I mean, React is smart enough just to replace the handler, not to re-render the DOM, right? so the cost is not that high?
I feel obliged to inform you that using an Anonymous function and Function.bind(this) in the render triggers a new render. This is because both
doIt.bind(this, 'myId') === doIt.bind(this, 'myId') // false
AND
() => doIt('myId') === () => doIt('myId') // false
are FALSE!
If you want to bind something to a function, use partial application with a method in the React class.
class myComponent extends Component {
doIt = (id) => () => {
// Do Something
}
render() {
<div>
<a onClick={this.doIt('myId')}>Aaron</a>
</div>
}
}
For:
small components: you are ok (almost no performance issues)
large components: the deeper you get the more try to avoid it
In React documentation about event handling, you can find:
In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.
Note: React is not handling callback props differently than other props. It always compares the old and new prop. Thus it re-renders when anonymous function is present because the anonymous function is always newly created.
Your JSX code sample should actually look like this:
<a onClick={ ()=>doIt('myId') }>Aaron</a>
Using an anonymous fat arrow function like this is perfectly valid. You are supposed to use anonymous functions in react attributes. That's okay.
Yes, it's not a best practice. If you want to solve the this context issue when using the ES6 class extends React.Component syntax I would advise you to bind the function in the class constructor.
No, for a 'small' component (i.e. not table where every row has a link) this is not a significant performance issue. You are safe.

Categories

Resources