I've read that it's good practice to declare function as component's method instead of inlining it in render, because every time parent component is rendered it creates new function and messes up with child's shouldComponentUpdate.
I.e. this:
<button onClick={this.handleClick} />
is better than that: <button onClick={e => someAction(e)} />
But what about curried functions? Is the following considered as creating new function?
class Parent extends Component {
handleClick = data => event => someAction(data);
render() {
const data = 123;
return <button onClick={this.handleClick(data)} />;
}
}
I know that the "performance impact" may be unnoticable there, but I find partially applicating function paramaters while passing down the component tree very convienent and I'm wondering if it's against best practices.
Yes it has negative performance impact because of the extra function invocation. But do you really have to worry about it? Most likely not. There are popular React patterns that use closures in render, like https://reactjs.org/docs/render-props.html Measure first to avoid spending energy on imaginary performance bottlenecks.
Yes. Every time you execute handleClick you will get in return a new function. In other words purpose of handleClick is to return a new function. If you remove some of the implicit syntaxes you will get:
handleClick = data => {
const innerFunction = event => someAction(data);
return innerFunction;
}
Side note: I've read some benchmarks that such performance impact by creating functions in render may have less impact than most people think.
Related
In terms of writing components, which would be the preferred way to write below component? Assume that removeCard is outside of shown scope, ie. redux action.
My assumption would be that ComponentCardB would be, as it avoids passing an unnecessary argument which would be in the scope anyway. I imagine in terms of performance in the grand scheme of things, the difference is negligible, just more of a query in regards to best practise.
TIA
const ComponentCardA = (id) => {
const handleRemove = (cardId) => {
removeCard(cardId);
};
<div onClick={() => handleRemove(id)} />;
};
const ComponentCardB = (id) => {
const handleRemove = () => {
removeCard(id);
};
<div onClick={handleRemove} />;
};
With functional components like that, yes, there's no reason for the extra layer of indirection in ComponentCardA vs ComponentCardB.
Slightly tangential, but related: Depending on what you're passing handleRemove to and whether your component has other props or state, you may want to memoize handleRemove via useCallback or useMemo. The reason is that if other props or state change, your component function will get called again and (with your existing code) will create a new handleRemove function and pass that to the child. That means that the child has to be updated or re-rendered. If the change was unrelated to id, that update/rerender is unnecessary.
But if the component just has id and no other props, there's no point, and if it's just passing it to an HTML element (as opposed to React component), there's also probably no point as updating that element's click handler is a very efficient operation.
The second option is better way because using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison.
Also if you don't want to use syntax with props.id you rather create function component with object as parameter:
const Component = ({id}) => { /* ... */ }
Of course using arrow function is also allowed but remember, when you don't have to use them then don't.
Say I have a React component that looks like this:
const MyReactComponent = (props) => {
const my_function = () => {// do some stuff...}
return (
<div>
<p>
Hello {props.name}, would you like to eat a {my_function()}?
</p>
</div>
)
}
Would the code defining my_function be re-evaluated every time My_React_Component is used? (By "used", I mean "appears in the JSX.")
Yes. Sort of. Maybe no.
When executing a javascript function each line in the function will get executed/evaluated. So the function definition will be evaluated again each time your function is called. Since you are using a function component then yes, the function will get redefined not only each time your component is used but also each time it is re-rendered.
However, does it mean that javascript recompiles the function each time it is defined? Maybe. In theory javascript does not need to recompile the function. It only needs to create a new closure. In theory you do not need to recompile a function to create a new closure - you just need a copy of the function's stack frame. Due to heavy competition from Netscape4 onwards most javascript interpreters have been optimised to such an extent that almost no modern javascript interpreter will recompile the inner function again. So the slowest part of function definition happens only once.
Still, in theory this still gives class-based components a small advantage over function components: the function definition does not need to be evaluated again on each render. In practice the performance difference is very small.
If you really insist on avoiding reevaluating the function definition you can always declare it outside of the component. This will surely evaluate the function only once. However you cannot use closures to share variables with the function but this is not much of an issue as you can always pass the variables into the function. Declaring functions outside of components also encourage you to write pure functions because of the inability to share closures:
const my_function = (propsArgs) => {// do some stuff...}
const MyReactComponent = (props) => {
return (
<div>
<p>
Hello {props.name}, would you like to eat a {my_function(props)}?
</p>
</div>
)
}
Do you mean Used or re-rendered?
In case of when you meant Used:
Yes every component acts as it's own instance hence the methods are executed every time when the function is either called or component is rendered initially (if used on rendering), But if you use the component at multiple times on the DOM, it writes the script only once. The markup is duplicated for that part of DOM, however the script isn't.
when only initialize, maybe you can use
React.useEffect(() => {
const my_function = () => {console.log('my_function')}
my_function();
}, [])
Is there any performance penalty for defining arrow functions in React function-based component's return statement rather than in the body of the component? For example, which is better and why, this:
const Test = () => {
const [isPopupOpen, setPopupOpen] = React.useState(false);
return (
<Popup handleClose={() => setPopupOpen(false)}>Anything</Popup>
)
}
VS
const Test = () => {
const [isPopupOpen, setPopupOpen] = React.useState(false);
// we use a hook so we cannot move it out of the component entirely
const closePopup = () => setPopupOpen(false)
return (
<Popup handleClose={closePopup}>Anything</Popup>
)
}
Both do exactly the same thing other than that the second one creates a binding within the function's execution context (loosely, a "variable") while the first doesn't. That's not going to impact your performance in any noticeable way.
No it won't effect any performance impact over the application. Provided the second one will help you implement any business logic before updating the state. Infact you can do it with the first one also, but for the sake of readability in case you want some extra logic second one will be preferred. Otherwise for a direct narrow implementation, you're good to go with the first one.
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>
);
};
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
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.
I've recently learned that passing down object literals or functions as props can cause unnecessary re-renders. As I am doing an audit on my app, I am finding some cases where I have common components that have callbacks on events that do different things. It's unclear to me what the most elegant way to handle this would be.
So for example in my app I have a component called SharedBtn that is used all over the app multiple places and in large loops. This button has an onClick listener. But in every instance this onClick is used we are passing down a different function to do a different thing every time.
Example:
https://codesandbox.io/s/k31120vnyo
I read this related article with examples. But their solution is to move the onClick logic to the shared component. This would be ugly for me as it is used in many different spots with many different handlers. How could I have the multiple click handlers without moving the click handling logic to the SharedBtn component itself?
You could create a small wrapper component for each special instance.
class IndexSharedButton extends React.PureComponent {
handleClick = e => {
this.props.onClick(e, this.props.index);
};
render() {
return <SharedBtn copy={this.props.copy} onClick={this.handleClick} />;
}
}
class AnimalSharedButton extends React.PureComponent {
handleClick = e => {
this.props.onClick(this.props.animal, this.props.type);
};
render() {
return (
<SharedBtn copy={this.props.animal} onClick={this.handleClick} />
);
}
}
You could also manually manage caching the bound handlers, but IMO that's pretty ugly and much less idiomatic.
Also, I think it goes without saying that you shouldn't worry about this much at all if you haven't measured it to be an actual issue. Re-renders don't happen that often, and with shouldComponentUpdate should happen even less. Optimizations like this add more code for little benefit.
Most of the time the performance hit is negligible. But the correct way to mitigate this in the age of hooks is via useCallback.
import { useCallback } from "react"
const MyComp = () => {
const func = useCallback(() => doSomething(), []);
return <OtherComp func={func}/>
};