Open utterances-bot opened 1 year ago
I've created ESLint plugin to detect unnecessary useMemo https://github.com/shashkovdanil/eslint-plugin-usememo-recommendations
what about if a memo is used to create a reference object and pass it as a prop? what about politics - avoid unnecessary rendering rather than doing a simple calculation?
Absolutely wrong way to test performance of the memo:
const startTime = performance.now();
const result = expensiveCalculation;
const endTime = performance.now();
@shashkovdanil Nice work out there!
@sergeysova Hey, can you please elaborate on this? Why it's wrong?
@Devisione
What about if a memo is used to create a reference object and pass it as a prop?
Yup, I like this idea. I assume we are speaking about something like this idea.
import React, { useState, useMemo } from 'react';
// ChildComponent receives a reference object as a prop
const ChildComponent = ({ data }) => {
console.log('ChildComponent rendering');
// Use the data from the prop
return <div>Data: {data.value}</div>;
};
// ParentComponent creates a reference object and passes it to ChildComponent
const ParentComponent = () => {
const [count, setCount] = useState(0);
const referenceObject = useMemo(() => {
return { value: count };
}, [count]);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<button onClick={handleClick}>Increment Count</button>
<ChildComponent data={referenceObject} />
</div>
);
};
export default ParentComponent;
what about politics - avoid unnecessary rendering rather than doing a simple calculation?
I stay away from politics in general and bring systems instead. So, if you can agree within a team on what approach to use - stick to it.
@ummahusla I guess in this sample expensiveCalculation
used as result of calculation but not as calling
@ummahusla if I'm reading this correctly, this code:
const startTime = performance.now();
const result = expensiveCalculation;
const endTime = performance.now();
Is measuring the time that JS takes to create a new reference in memory and assign it the value of another reference. It does not call any actual function that would do any work worth measuring. expensiveCalculation
contains the result of the memo. So the result for endTime - startTime
will be constant and almost zero every time.
@ummahusla another use-case I found myself using useMemo
for is in order to avoid unnecessary renders. For example if I need to convert one value to some other shape and for this I create a new object. The calculation is cheap and I don't mind creating a new object, but it will trigger a render in the lower parts of the component tree, which I want to avoid.
Would you still recommend useMemo for this, or do you have another pattern?
@ummahusla if I'm reading this correctly, this code:
const startTime = performance.now(); const result = expensiveCalculation; const endTime = performance.now();
Is measuring the time that JS takes to create a new reference in memory and assign it the value of another reference. It does not call any actual function that would do any work worth measuring.
expensiveCalculation
contains the result of the memo. So the result forendTime - startTime
will be constant and almost zero every time.
Hey, thanks for your reply. I think I see where you coming form. I'm playing around with this component right now and will update the blog post at some point:
import React, { useState, useMemo } from "react";
const MemoComponent = () => {
const [count, setCount] = useState(0);
const expensiveCalculation = useMemo(() => {
const startTime = performance.now();
// Simulate an expensive calculation
let result = 0;
for (let i = 0; i < 10000000; i++) {
result += i;
}
const endTime = performance.now();
console.log("Expensive calculation execution time:", endTime - startTime);
return result;
}, []); // Include 'count' as a dependency if you want to recompute when it changes.
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<button onClick={handleClick}>Increment Count</button>
<p>Count: {count}</p>
<p>Result: {expensiveCalculation}</p>
</div>
);
};
export default MemoComponent;
@ummahusla another use-case I found myself using
useMemo
for is in order to avoid unnecessary renders. For example if I need to convert one value to some other shape and for this I create a new object. The calculation is cheap and I don't mind creating a new object, but it will trigger a render in the lower parts of the component tree, which I want to avoid.Would you still recommend useMemo for this, or do you have another pattern?
@amiiit My blog post was published on the /r/reactjs
subreddit, and it was a blast. Lots of healthy discussions and related articles were posted, have a look around.
One link in particular I found interesting - https://attardi.org/why-we-memo-all-the-things/, I even emailed its author, to figure out whenever anything changed. This is his response:
Nothing changed. If anything we doubled down. I helped create a team called Client Foundations responsible for front-end code at the entire company. I personally led multiple efforts to fix performance of various React and React Native codebases and the biggest gains we’ve seen came from adding memoization where it was missing. And we also wrote custom lint rules to enforce memoization everywhere. I think the solution is for React to build a compiler to memoize things automatically so we can end this debate once and for all. I think it’s coming.
useMemo overdose | Edvins Antonovs
When overuse of useMemo hook becomes a problem
https://edvins.io/usememo-overdose