Reputation: 63
If declaring an arrow function inside a react class component is bad for performance, why does declaring variables(arrow functions) inside a functional component have better performance?
The way React is now moving towards using the entire app with only functional components, won't it have performance issues for big apps that have long component trees with lots of variables that being redeclared on each update? (I know some are garbage collected but the declaration still occurs, same as using arrow function inside the render function of a class component)
class ReactComponent extends React.Component {
render() {
return (
<div onClick={() => console.log('do something')}>
<SomeOtherComponent onChange={() => console.log('pass function')} />
</div>
);
}
}
const functionalComponent = () => {
const doSomething = () => console.log('do something');
const passFunction = () => console.log('pass function');
return (
<div onClick={doSomething}>
<SomeOtherComponent onChange={passFunction} />
</div>
);
};
Upvotes: 4
Views: 1351
Reputation: 138267
Nothing is "bad for performance", there are only unnecessary computations. If creating a function is necessary to express the behaviour of a program, there is nothing "bad". It is only "bad" if creating the function can be avoided, and it is even worse if a lot of computations can be avoided.
Creating a function is cheap. It creates a new function object, that contains a reference to the functions code as well as to it's environment (the "closure"), so a function expression is not much different than an object literal. Therefore creating functions is not "bad", and it never was.
The real problem that arises from function expressions in React, is not the function expression itself, but the logical result of it:
<div onClick={() => doStuff()}> Test </div>
On every rerender, a new function object gets created, that references a different environment, that might contain a different doStuff
method, that might do something different. Therefore on every rerender, React has to detach the listener, and attach a new one referencing the new function, so that the new behaviour gets triggered. For one listener this is cheap, but if you pass down functions to other components, that pass down functions to other components, the cost multiplies (= more components have to rerender), so it might get expensive (= something we might worry about). If the function changes, but what it does does not, reattaching the listeners is uneccessary, and thus it can be avoided by making sure that functions only get recreated when the values they depend on get recreated:
const callback = useCallback(() => doStuff(), [doStuff]); // returns the same function, unless doStuff changes
<div onClick={callback}> Test </div> <- only gets reattached when doStuff changes
Upvotes: 4
Reputation: 84982
If declaring an arrow function inside a react class component is bad for performance
The reason people warn you about creating functions on every render is not because creating functions is slow. It's not; creating functions is very fast.
The performance issue comes when you pass that function to something else, and that something else is using shouldComponentUpdate or PureComponent or React.memo or useMemo or some other form of memoization. Since it received a new function, it thinks it needs to recompute, and so the memoization benefit is lost.
It's true that this issue can occur in function components too, but that's one of the things that useCallback and useMemo are for. You can use those hooks to create the function only once, and thus you will not needlessly break memoization of other components.
Upvotes: 1