ReactJS - inline arrow functions performance - javascript

I have read that using an arrow function inline re-creates the function on every component re-render causing performance issues.
In my code I have this situation
render() {
return (
<View
onLayout={(event) => {
this.itemHeights[index] = event.nativeEvent.layout.height;
}}
>
...
)
}
I have thought to do something like this to get a better performance:
getItemHeight = (index, {nativeEvent: {layout: {height}}}) => this.itemHeights[index] = event.nativeEvent.layout.height;
render() {
return (
<View
onLayout={(event) => getItemHeight(index, event)}
>
...
)
}
But I am not really sure if this is better... at I have to invoke a function in a inline function. I did it because I need the parameter index, so I can't do:
<View
onLayout={getItemHeight}
>
I know that this may not be too expensive, but it is very expensive for my use case, as I have to re-render items on the fly.
Any ideas?

Declaration vs Execution
First of all I think you are confusing two things here.
The declaration of a function is something different than the execution of a function.
Also the component does not re render all the time, just because a function is redeclared inside the render functions return.
There is also a vast difference between the performance impact between the declaration of a function and its execution.
Referentially stable function vs inline functions
So what you are doing in your first example is redeclaring a function for the View component. This basically resets the value for the onLayout prop, because inline functions are not referentially stable.
~~In the second example (I figure this is a class component), you are using a referentially stable function, so the prop value of onLayout stays the same.~~
UPDATE: Actually this is not true, my bad. You are still using a instable function. But you could just bring that up as a class member like so:
public getItemHeight(index, {nativeEvent: {layout: {height}}}) {
this.itemHeights[index] = event.nativeEvent.layout.height;
}
// ...
// ... inside the render function:
return {
<View onLayout={this.getItemHeight}></View>
}
But I am not really sure if this is better... at I have to invoke a function in a inline function. I did it because I need the parameter index, so I can't do:
Actually this statement isn't true. You can also retrieve the index with a defined function, as I showed above.
Using this code you are just giving the prop a reference to the function that you want to be invoked by the callback. This will populate the arguments just fine.
When do components re render?
Components re render when there is a prop or state change.
So in your first example the View component will re render only if the parent component has to be re rendered. So the parent renders and therefore evaluates the it's sub components. This does trigger the render function of the View component and swaps out the function for onLayout.
In your second example (considering my suggested code change above) the View component would not trigger it's render function since the prop value of onLayout did not change.
But that does not mean, that your first example necessarily results in a DOM change and repaint (this is a different algorithm inside React). And the DOM change would be the really expensive part.
Rerender vs Repaint
Rerender is a process that React runs internally. React just triggers the render functions of the component that have to be rerendered. But the repaint inside the actually page during runtime only happens if the resulting DOM is different than before.
You can read more about this in the React Docs: https://reactjs.org/docs/reconciliation.html
So when would you have to use referentially stable functions?
I don't think that you should prematurely optimize such things. It can make the code more bloated and introduce complexity that isn't always necessary.
There is also a whole part on this here: https://reactjs.org/docs/optimizing-performance.html#avoid-reconciliation
If it does not drain your performance, why bother micro optimizing things?
Just because you read that inline function are recreated every time (btw. this also applies to non arrow functions. It's the inline declaration that makes it recreate every time) and therefore the render function is triggered every time, doesn't always mean that React has to repaint or that it has a big performance impact.
So never prematurely fiddle around on small performance gains, when there isn't even a problem.
An React based app is a huge beast of code. There will be plenty big picture problems to fix, once you run into performance issues.

Related

Converting React ES6 class to functional component - what to use for private methods?

I'm converting a React ES6 class-style component to a functional component. The one thing I'm slightly unsure of is how best to convert private class methods. As far as I can tell, I should convert them to functions within the functional component's function, as they need to be there to access the component's state. However, that presumably means that on each re-render, the function is going to get recreated:
Before
class Game extends React.Component {
handleClick(i) { if (this.state.foo) { ... } }
}
After
function Game {
function handleClick(i) { if (foo) { ... } }
}
Is this a problem performance-wise, and if so, is there any way to improve it?
Also, most guides I've read recommend assigning arrow functions to variables instead of just declaring functions, eg.
function Game {
const handleClick = (i) => { if (foo) { ... } }
}
Is this purely stylistic, or is there another reason to use assigned arrow functions over regular nested function definitions?
You can use functions defined with either the function keyword or the arrow function syntax. It does not really make a difference in this case. However, with the arrow syntax, functions do not get hoisted, and that may cause the linter to report a warning if you use a function before it is defined.
However, that presumably means that on each re-render, the function is
going to get recreated
You are correct, if you define functions either way, they will get recreated on every re-render. Whether that's a problem or not will depend on your use case.
If you use such a function inside a useEffect callback and add it to its dependency array, the effect will re-run on every re-render (which may not be what you want). If you pass such a function as a prop to any child component(s), that component(s) will also re-render.
You can wrap the functions in question with useCallback, and any child components that receive these as props with React.memo. However, you are now trading the cost of re-rendering components for the cost of storing and comparing props (React will be doing this, not you).
So really, this depends on your app. If the component in question has a large component tree below it, going with useCallback and React.memo might be worth it.

Understanding JavaScript object properties (functions) referencing other properties in same object

So I have stumbled upon a React Hooks based component that uses objects to categorize various functions for readability.
For eg.
const MyComponent = (props) => {
const utilities = {
utility1: () => {
// ...some functionality
},
utility2: () => {
// ...some functionality
},
};
const renderers = {
renderer1: () => {
// ...some rendering logic
},
renderer2: () => {
// ...some rendering logic
return (
<span>{renderers.renderer1()}</span>
);
},
};
return (
// ...rendering logic
);
};
What I want to understand is why is renderer2 working correctly even when it calls renderer1?
What I understand is that the object will be declared when the code is executed and the declaration is not complete till all properties are defined (this is just my noob understanding, I may be entirely wrong).
I would be really interested in knowing why this little bit of code works, especially why does it work correctly?
Also, on a side note, compared to Class-based components, I feel Hooks-based components are not very readable, and this approach tries to mitigate the problem. So I was wondering if this is the best way to make a Hooks-based component readable, or if there are other better approaches for the same?
What I understand is that the object will be declared when the code is executed and the declaration is not complete till all properties are defined
This is not so. A variable declaration happens ahead of time - at compile time, before any code actually has had a chance to run. The assignement to a variable happens at runtime though. This includes evaluating the value being assigned.
So in the case you're talking about, when the object being assigned to renderers is being evaluated, the renderers variable is actually already declared.
Also, you have to consider the fact that renderers.renderer1() is not actually being called as part of the evaluation of this object - but only later on when renderers.renderer2() is actually be called, at which point both the object evaluation and the assignment will have completed, and thus renderers.renderer1() will be what you expect it to be.

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)

What is the difference between using setItem to set multiple state values and using useEffect to do so?

I have a reset button in my app that resets a few variables of my functional component:
const [selectedItem, setSelectedItem] = useState(0);
const [a, setA] = useState('a');
const [b, setB] = useState('blue');
<button onClick={e => ???}>clicky</button>
<button onClick={e => ???}>clicky</button>
There are two ways I could 'reset' the data: monitoring selectedItem for changes using useEffect, or have a handler that does so:
<button onClick ={e => setSelectedItem(e.target.value)} />
useEffect(() => {
setA(Math.random())
setB(Math.random())
}, [selectedItem])
or
<button onClick ={e => handler(e.target.value)} />
const handler = item => {
setSelectedItem(Math.random())
setA(Math.random())
setB(Math.random())
}
What are the practical differences between these approaches? The hooks docs say to use useEffect for performing side effects, but I can't see why this approach wouldn't work as well.
What is the difference between these approaches?
I will try to answer this question in three points.
Mental model
You need to "think in effects". the UseEffect hook lets you perform side-effects that manly need to happen async like (fetch Data from API, manipulate the DOM).
based on that it's better to use UseEffect to handle side-effects so you are not confusing your colleges.
Async
You need to keep in your mind that useEffect is an async function but your event handler is sync function. That can lead to totally different behavior maybe you are not seeing a weird behavior here but maybe in other examples, you will start to notice that.
React mechanism
the last difference to notice it you need to understand React update state mechanism, react makes patches to update the state. That means in your event handler the three-state will cause one re-render because they will happen at the same time. In your useEffect that is not the case, you are updating one of them that case re-render then you are performing the effect that will case new re-render.
Maybe there are other differences but that what can I see right now.
I hope it’s a useful answer.
There are a few peculiar differences between the above two methods.
In the first method of using useEffect, you would be updating states a and b whenever selectedItem changes, be it by a button click or some other sideeffect such as a prop change. However in the second case, states a and b would only be updated if selectedItem is updated on button click and you would need to call setA and setB to update states everywhere you update selectedItem separately
Secondly, when you are using a useEffect to update state, the state update will happen after updating selectedItem, however in the second case state updates doesn't gurantee that selectedItem is updated before setting the other states and hence if the other state updated depend on selectedItem value, you need to pass the updated selectedItem value to the other state updaters separately
In short, making use of useEffect is better when you know you have to take other actions whenever a state change occurs no matter how it occurs. Also its useful when you want to take action after a particular state is updated.
I believe it's important to consider the semantics of what you're doing. For example:
<button onClick ={e => handler(e.target.value)} />
const handler = item => {
setSelectedItem(Math.random())
setA(Math.random())
setB(Math.random())
}
this means that whenever you click the button you want the 3 state variables to be changed.
On the other hand:
<button onClick ={e => setSelectedItem(e.target.value)} />
useEffect(() => {
setA(Math.random())
setB(Math.random())
}, [selectedItem])
this means whenever you click the button you want that one state variable to change and independently of that you want, whenever that one state variable changes, to change those other two state variables.
The real question you should be asking is what is it you really want to express with your code, given that it has the same end result. In short, what makes semantic sense to you? Does it make sense to say "this button can be used to change those 3 state variables" or does it make more sense to say "this button can be used to chanage the selectedItem state variable and this entire component will change the a and b state variables whenever the selectedItem changes?
It is usually important to make sure your code makes semantic sense so you don't land in the pitfalls of getting unintended side-effects when you make code changes. For example, if selectedItem ends up being changeable by other means, the 2nd method will ensure that a and b change at the same time. Do you really want that?
There's also a practical consideration. There's the eslint rule called react/no-did-update-set-state which states:
Updating the state after a component update will trigger a second render() call and can lead to property/layout thrashing.
Layout thrashing basically means there's multiple potential redraws of the layout before a user can interact with it again. In the case of useEffect this can be an issue because useEffect is triggered after a layout update and setting the state might trigger another one. It usually has no noticeable effect on very simple operations but if you have a complex component hierarchy and end up re-rendering large portions of it then you will end up with a less responsive layout.
There's also the additional consideration that with the useEffect you also need to be mindful to avoid cyclical dependency changes e.g. selectedItem changes a and a changes selectedItem or makes a change which ends up changing selectedItem somewhere further down the line.
So overall there are three notes:
Use whichever makes more semantic sense for your component
Be aware of potential layout thrashing
If useEffect does make more sense take a step back and really think about why it makes more sense and whether there is a better way to solve your problem and at the same time avoid using useEffect to set state variables.
Ok the scenario you are referring to here is not really a side-effect, or I would say the side-effect react refers to. React refers to side-effect like if you are doing a network request
In your case if you just want to reset some variables I think having a clickHandler is the way to do, you would use a useEffect like if you want to do a network request when the component loads or some props change
Hope it clarifies

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