React JS binding callbacks - javascript

How can we practically prove the point, After Every render react creates new callback arrow function so it is a bad approach. See below code -
class DankButton extends React.Component {
render() {
// Bad Solution: An arrow function!
return <button onClick={() => this.handleClick()}>Click me!</button>
}
handleClick() {
this.logPhrase()
}
logPhrase() {
console.log('such gnawledge')
}
}
Also, how the below Arrow function class property function really works ?
class DankButton extends React.Component {
render() {
return <button onClick={this.handleClick}>Click me!</button>
}
// ES6 class property-arrow function!
handleClick = () => {
this.logPhrase();
}
logPhrase() {
console.log('such gnawledge')
}
}

I'm not sure i understand what you mean exactly by
How can we practically prove the point
As i understand from your question, i assume that you do realize that in the first example above, a new instance of a function is being created.
With that in mind, when you think about it, there are at least 2 issues when you create and pass a new instance of an object or function:
Maybe less important in most cases, you consume more memory on each
render.
More important (in my opinion) you can potentially interrupt the
Reconciliation and Diffing Algorithm of react by passing a new
prop on each render, this will cause a re-render of the child
component, hence performance issues can arise.

Arrow function class property function really works.
Sorry, Don't know how to prove the new instances of function when using bind, but I can do the latter.
console.log this in your arrow function, and compare it to one that is done as a regular function. Do not use bind at any point. The arrow function's this will be the component's context, while the function based one will be either window or undefined.

Related

Declaring function inside function in React

I just came across a React code and I'm not sure whether it's is a good way to do it or not. This is a sample implementation of that code.
class App extends React.Component {
renderMessage = () => {
function getMessage() {
return "Hello"
}
function getName() {
return "Vijay"
}
return (
<h1>{getMessage()} {getName()} !!!</h1>
)
}
render() {
return (
<div>
{this.renderMessage()}
</div>
)
}
}
Here we are calling a function renderMessage inside render. In renderMessage there are two inner functions which are called inside renderMessage only. My question now are:-
Is it a good approach to do? Won't it redeclare method getName and getMessage at every render call.
If I make getName and getMessage class methods and call them inside renderMessage would it be an improvment?
Thanks :)
Is it a good approach to do? Won't it redeclare method getName and getMessage at every render call
Definitely not a good approach. As JavaScript is either having functional or block or global scope.
Whatever you defining at this scope will be part of this scope only.In your case, these function getMessage and getName will be part of renderMessage which is functional scope.
At every call, new functions are getting defined instead reusing previously defined.
If I make getName and getMessage class methods and call them inside renderMessage would it be an improvement?
Depend.
If this function need an access to any component properties or method then you should place it inside the component or If this is only utility function then place it inside helper library separate from component.
Surely, this will make difference.
Is it a good approach to do? Won't it redeclare method getName and getMessage at every render call.
It will redecleare functions getName and getMessage at every render call. It's not great, but not terrible. This approach reduces bugs with rerendering - the function declaration is part of the render result. Although in your exact case it doesnt matter, as the functions will always return the same result and it doesnt depend on the state (although in that case it'd be more readable to just inline the strings)
If I make getName and getMessage class methods and call them inside renderMessage would it be an improvment?
It will make virtual life easier for the garbage collector. The chances are, once you start depending on global state, this will start to go wrong, e.g.:
class App extends React.Component {
getMessage => () {
return "Hello"
}
getName => () {
return this.props.name
}
renderMessage = () => {
someHttpAction().then(() => {
alert(getMessage() + ' ' + getName());
})
}
render() {
return (
<div onclick={this.renderMessage}>Say my name! (Hint, its {this.props.name})</div>
)
}
}
(Note that name is passed in as an argument to App)
When you render the first time, you might expect that, after clicking the text, you'll see an alert of "Hello Vijay". That's true, most of the time. But what happens if, after you click the text, you rerender with a different value for name, say Heisenberg, while someHttpAction promise still has not resolved? You might expect to see your name - Vijay, but actually you'll see the new value, "Hello Heisenberg". By declaring the function inline (as per your example), the function's scope is locked and you'll get the expected result "Hello Vijay".
Imagine a bit more complex scenario where you switch between multiple user profiles and the async messages start showing up on the wrong user...
While yes, we could pass name as an argument to getName, in reality, people think "its fine this time" or forget, and this is how bugs get introduced. Much less difficult to make the same mistake with inline functions. Unless this becomes a bottleneck, stick with the less errorprone approach.
Also, I suggest skimming through How Are Function Components Different from Classes?
It is possible, but it is not a good solution at all.
Yeah, it creates new function on each re-render, but it's not a case if you don't pass them as props.
The problem is that you can get a giant monster component with very ambiguous responsibilities in the nearest future.
Even more. It is bad in terms of performance. The bigger your component is, the bigger time it needs for re-render. And each smallest change will re-render the whole component, not only its part.
You should move renderMessage method to the new component for the sake of readability and scalability.
class App extends React.Component {
render() {
return (
<div>
<Message/>
</div>
)
}
}
class Message extends React.Component {
getMessage() {
return "Hello"
}
getName() {
return "Vijay"
}
render() {
return (
<h1>{this.getMessage()} {this.getName()} !!!</h1>
)
}
}

Function inside functional component in React hooks - Performance

Need suggestion on having function within a functional component in react Hooks.
As far as I researched, many are saying it is bad practice
because it creates nested/inner function every time we call re-render.
After doing some analysis,
I found we can use onClick={handleClick.bind(null, props)} on the element and place the function outside the functional component.
Example:
const HelloWorld = () => {
function handleClick = (event) => {
console.log(event.target.value);
}
return() {
<>
<input type="text" onChange={handleClick}/>
</>
}
}
Please advise if there is any alternative way.
Thanks in advance.
Don't worry about it
Don't worry about creating new functions on each render. Only in edge cases does that impede your performance.
Setting onClick handlers are not one of those, so just create a new function on each render.
However, when you need to make sure you use the same function every time, you can use useCallback
Why not use useCallback for onClick
Here is a reason why you shouldn't bother with useCallback for onClick handlers (and most other event handlers).
Consider the following code snippets, one without useCallback:
function Comp(props) {
return <button onClick={() => console.log("clicked", props.foo)}>Text</Button>
}
and one with useCallback:
function Comp(props) {
const onClick = useCallback(() => {
console.log("clicked", props.foo)
}, [props.foo])
return <button onClick={onClick}>Text</Button>
}
The only difference in the latter is that React doen's have
to change the onClick on your button if props.foo remains the same.
Changing the callback is a very cheap operation, and it's not at all
worth complicating your code for the theoretical performance improvement it gives.
Also, it's worth noting that a new function is still created on every render
even when you use useCallback, but useCallback will return the old one
as long as the dependencies passed as the second argument are unchanged.
Why ever use useCallback
The point of using useCallback is that if you compare two functions with reference
equality, fn === fn2 is true only if fn and fn2 point to the same function in memory.
It doesn't matter if the functions do the same.
Thus, if you have memoisation or otherwise only run code when the function changes,
it can be useful to use useCallback to use the same function again.
As an example, React hooks compare old and new dependencies, probably using Object.is.
Another example is React.PureComponent, which will only re-render when props or state have changed. This can be useful for components that use a lot of resources to render. Passing e.g. a new onClick to a PureComponent on each render will cause it to re-render every time.
many are saying it is bad practice because it creates nested/inner function every time we call re-render
No, inner functions / closures are so common, there is no problem with them. The engine can heavily optimize those.
The point here is that you pass the function as a prop to the child component. And as the function was "recreated", it does not equal the previous function passed, annd thus the child does rerender (and that's whats bad for performance).
You can resolve that with useCallback, which memoizes the function reference.
Interesting question, me and my coleagues had some worries about this, so I did a test.
I have created 1 Component with Hooks and 1 Component with Class, put some functions there and then render it 1000x times.
The Component with Class looks like this:
export class ComponentClass extends React.PureComponent {
click1 = () => {
return console.log("just a log");
};
render() {
return (
<>
<span onClick={this.click1}>1</span>
</>
);
}
}
The Component with Hooks looks like this:
export const ComponentHook = React.memo((props) => {
const click1 = () => {
return console.log("just a log");
};
return (
<>
<span onClick={click1}>1</span>
</>
);
});
I have added more click handlers to the components and then rendered them some 1000s times, the Class is faster as it does not define the functions each render, if you increase the number of functions defined, then the difference will be bigger:
Here it is a codesandbox so you can test the performance Class vs Hooks : https://codesandbox.io/s/hooks-vs-class-forked-erdpb
useCallback
You can use useCallback feature :
const HelloWorld = ({ dispatch }) => {
const handleClick = useCallback((event) => {
dispatch(() => {console.log(event.target.value)});
})
return() {
<>
<input type="name" onChange={handleClick}/>
</>
}
}
useCallback will return a memoized version of the callback that only
changes if one of the dependencies has changed. This is useful when
passing callbacks to optimized child components that rely on reference
equality to prevent unnecessary renders (e.g. shouldComponentUpdate).
For further details visit react documentation reference: React useCallback
Old Solution
First solution:
To pass the your handleClick function to your functional component.
const HelloWorld = (props) => {
return() {
<>
<input type="name" onChange={props.handleClick}/>
</>
}
}
Second solution:
To define your function outside of your functional component.
Inspired by #tibbus 's benchmark, I made this one that tests the perfomance using or not the useCallback hook. After several executions, it seams that the use of useCallback can be very important for high frequency rendering.
Execution 1
Execution 2
Execution 3
https://codesandbox.io/s/usecallback-vs-raw-definition-xke9v?file=/src/App.js
As per React Documentation (ending part),
The problem with latter syntax is that a different callback is created
each time the LoggingButton renders. 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.
Class field syntax:
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
arrow function in the callback syntax:
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
I would honestly just use a class component in these cases. I'm aware of premature optimization, but creating a new function each time does just seem like extravagant wastefulness without much of a maintainability upside. tibbus has demonstrated the perf hit, and inline functions are arguably less readable than class methods. All you're losing out is the slick feeling of writing a functional component.
Just useCallback
Why would you need to define a function inside a component and not anywhere else? Because you either have to pass it to another child compononent, or you have to use it in an effect, memo, or another callback. For any of those cases if you dont wrap your function in useCallback you will be passing a new function and causing the component to rerender, the memo to re-run, the effect to re-run, or the callback to re-define.
You can never avoid the performance hit of redefining the function itself, but you can avoid the performance hit of performing any computation that has that function as a dependency to know if it has to run or not (be it a component or hook).
So... just wrap every function in your component in useCallback and forget about it, never seen a single in case in which this would cause any harm. If you can define the function outside the component, thats always better.

Where should I bind methods in React component?

I learn React now and noticed that a lot of people bind their methods in constructor.
Like this:
class MyComponent extends React.Component {
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod() {
// do something
}
}
But I got used to writing something like this:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
And I was told by a couple of people that using the second method is a bad experience.
So could you tell me the differences between first and second methods? Any pros and cons? or performance issues?
You are right and what others told you is also right.
You are encouraged to do binding in constructor because constructor gets called only once per component so if you do binding in constructor it creates a new object/function only once in Webpack bundle.js file hence not much impact
You are not encouraged to do binding directly in render because a component renders for several reasons like when you do setState, when your component receives new props so your component will render so many times. So since you are binding directly in render whenever your component renders it will create a new function every time in Webpack bundle.js and your bundle file size will increase and that affects performance when your app contains thousands of components and if you do binding directly in render in every component.
So you are recommended to do binding only in constructor. Hope that clarifies
This results in creating a new bound function on every render call:
render() {
<button onClick={this.myMethod.bind(this)}>Click me</button>
}
Notice that if myMethod is used in multiple places, this requires multiple bind calls and may result in unbound callback if one of bind is missing.
While this creates bound function on component instantiation:
constructor() {
super();
this.myMethod = this.myMethod.bind(this);
}
The second option is recommended.
A decorator like autobind can be used to skip myMethod explicit assignment in constructor.
As explained in this answer, prototype methods with bind have less shortcomings than arrow instance methods and can be generally preferred.
You should bind in the constructor simply because the second way will create a new function every render.
But there's a better way to simply avoid binding. Use arrow function.
class MyComponent extends React.Component {
constructor() {
super();
}
render() {
<button onClick={this.myMethod}>Click me</button>
}
myMethod = ()=> {
// do something
}
}
Let's see how the creator of Redux Dan Abramov thinks about bind vs arrow functions -
Question:
In terms of performance, is there any difference between using arrow
functions and bind manually when using es6 classes? Using arrow
functions the methods are not on the class prototype, it will be on
the class instance only. Using bind will attach the methods to class
prototype. It sounds like bind manually will have better performance,
does that mean we should consider using bind instead of arrow
functions for class methods?
Any suggestions or comments are really appreciated!
So in terms of performance, would you recommend using
class MyComponent extends React.Component { constructor(props) {
super(props) }
methodA = () => { ... } }
or
class MyComponent extends React.Component { constructor(props) {
super(props)
this.methodA = this.methodA.bind(this) }
methodA() { ... } }
Answer:
These two ways of writing it are equivalent. (The second one is
compiled to the first one.)
Using bind will attach the methods to class prototype.
In your example, you still attach the function to the instance:
this.methodA = this.methodA.bind(this)
So they’re essentially the same.
At Facebook, we use the second way (“class properties”) but be aware
this is still experimental, and not part of ES6. If you only want to
stick with stable syntax, then you could bind them manually.
First approach is correct performance wise, because on every render this onClick prop will be pointing to the same object, which is not the case in the second example.
If you look at the below example, you will see when I increment the counter, the MyPureCompOne doesn't render, but MyPureCompTwo does. Because each time time the <App> component renders, MyPureCompTwo props handleClick being assigned with a new function object, and that is why being a pure component shallow comparisons of props are false and it renders. This rendering was not needed. But that is not the case with MyPureCompOne, as each time time App renders, the handleClick props still pointing to the same function object (this.handleClickOne) which was created when the App first time mounted.
class MyPureCompOne extends React.PureComponent {
render() {
console.log("rendring component one");
return <button onClick={this.props.handleClick}>First Button</button>
}
}
class MyPureCompTwo extends React.PureComponent {
render() {
console.log("rendring component two");
return <button onClick={this.props.handleClick}>Second Button</button>;
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
this.handleCountChange = this.handleCountChange.bind(this);
this.handleClickOne = this.handleClickOne.bind(this);
}
handleCountChange() {
this.setState(prevState => ({
count: prevState.count + 1
}));
}
handleClickOne(e) {
console.log("Clicked..");
}
handleClickTwo() {
console.log("Clicked..");
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.handleCountChange}>Change Counter</button>
<MyPureCompOne handleClick={this.handleClickOne} />;
<MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<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>
I took this from the eslint-plugin-react documentation:
A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary. It may also cause unnecessary re-renders if a brand new function is passed as a prop to a component that uses reference equality check on the prop to determine if it should update.
As a side note from me, using this in your JSX can be confusing as well. I encourage you to take a look at this doc: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
You should avoid arrow functions and binds in render. It breaks performance
optimizations like shouldComponentUpdate and PureComponent.
For an excellent read and demo you might want to refer
this.

Class properties for react lifecycle methods

Can I write React lifecycle methods as class properties?
I've been using class properties for a while as I like the fact that I no longer have to manually bind my methods, but I'd like to keep some consistency across my components and I'm wondering if there is any drawback on writing the React lifecycle methods as class properties
import React, { Component } from 'react';
class MyComponent extends Component {
render = () => {
return (
<div>Foo Bar</div>
);
}
}
export default MyComponent;
For example, is the context of this class property affected compared to the context in an equivalent method. Given that the render method in the above code is written as an arrow function, this concern seems relevant.
In a way, the true answer depends on your build pipeline and what the resulting Javascript output looks like. There are two primary possibilities:
Input Code
Let's start by saying you are writing the following before going through any sort of pipeline transformations (babel, typescript, etc):
class Test {
test = () => { console.log('test'); };
}
Output as class member variable.
In one possible world, your pipeline will also be outputting the test function as a member variable for the output class. In this case the output might look something like:
function Test() {
this.test = function() { console.log('test'); };
}
This means that whenever you write new Test() the test function is going to be recreated every single time.
Output as class prototype function
In the other major possibility, your pipeline could be recognizing this as a function property and escape it from the class instance to the prototype. In this case the output might look something like:
function Test() {
}
Test.prototype = {
test: function() { console.log('test'); }
}
This means that no matter how many times you call new Test() there will still be only one creation of the test function around in memory.
Desired behavior
Hopefully it's clear that you want your end result to have the function end up on the prototype object rather than being recreated on each class instance.
However, while you would want the function to not end up as a property, that doesn't necessarily mean you couldn't write it that way in your own code. As long as your build chain is making the correct transformations, you can write it any way you prefer.
Although, looking at the default babel settings (which your babeljs tag leads me to believe you are using) it does not make this transformation for you. You can see this in action here. On the left I've created one class with the function as a property and one class with the function as a class method. On the right hand side, where babel shows it's output, you can see that the class with the function as a property still has it being an instance-level property, meaning it will be recreated each time that class's constructor is called.
I did find this babel plugin, which seems like it might add this transformation in, but I've not used it for myself so I'm not positive.
In my experience, the most reason for writing a method as a class property is when the method will be passed as a callback, and you need it to always be bound to the instance. React lifecycle methods will always be called as a method, so there's no reason to bind them (and you incur a tiny memory penalty when you do). Where this makes a difference is when you're passing a function to a component as a callback (e.g. onClick or onChange).
Take this example:
class BrokenFoo extends React.Component {
handleClick() {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
The function represented by this.handleClick is not automatically bound to the component instance, so when the method tries to read the value of this.props it will throw a TypeError because this is not defined. Read this article if you're not familiar with this; the problem described in section 4.2 "Pitfall: extracting methods improperly" is essentially what's happening when you pass around a method without making sure it's bound correctly.
Here's the class, rewritten with the handler as a class property:
class HappyFoo extends React.Component {
handleClick = () => {
alert(this.props.message);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
)
}
}
Effectively, you can think of the handleClick definition in the second example as placing this code into the component's constructor (which is just about exactly the way Babel does it):
this.handleClick = () => {
alert(this.props.message);
}
This achieves the same thing as calling bind on the function (as described in the linked article) but does it a little differently. Because this function is defined in the constructor, the value of this in this.props.message is bound to the containing instance. What this means is that the function is now independent of the calling context; you can pass it around and it won't break.
The rule of thumb that I follow: by default, write methods as methods. This attaches the method to the prototype and will usually behave the way you'd expect. However, if the method is ever written without parentheses (i.e. you're passing the value and not calling it), then you likely want to make it a class property.

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
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/
when you define a new method inside a react component (Object) as we know functions are object in javascript.
let reactComponent={
addition: function(){ //some task ...},
render: function(){},
componentWillMount : function(){},
}
so, every new method should be bind with in the object using bind, but render() is already defined so we don't do
this.render = this.render.bind(this)
for each new function, except react lifecycle methods are needed to be added and hence, we call the object (constructor function) methods using this.method().

Categories

Resources