Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
160
rated 0 times [  163] [ 3]  / answers: 1 / hits: 5557  / 3 Years ago, sat, january 30, 2021, 12:00:00

Lately I've been thinking about ways to memoize some children components of a functional component, based on Dmitri's how to use React.memo wisely. These children components may / may not be using some props from the main component.


Let the component be written like so:


export const MainComponent = ({a, b}) => {
const AComponent = React.memo(() => <p>This is the string of {a}</p>)

return (
<div>
<AComponent />
<p>This is the string of {b}</p>
</div>
)
}

Say the MainComponent is re-rendered several times over its lifecycle in a parent component.


const App = () => {
const [a, setA] = useState(0); // a is update only when a button is pressed
const [b, setB] = useState(0); // b is updated every 1 second

const onClick = () => setA(a => a + 1);

useEffect(() => {
const interval = setInterval(() => setB(b => b + 1, 1000);
return () => clearInterval(interval);
}, []);

return (
<div>
<MainComponent a={a.toString()} b={b.toString()} />
<button onClick={onClick}>increment a</button>
</div>
)
}

I understand that as states a and b in the App are updated, it needs to be re-rendered, which in turn has to re-render the MainComponent which depends on a and b.


There are 2 questions:



  1. When the interval updates b in App, a is not updated at all, so when the MainComponent re-renders, should it use the memoized AComponent, not paying the cost of rendering?



  2. I do know that when the button is pressed, a in App is updated, which makes MainComponent re-render; the AComponent cannot use the memoized version, so it needs to pay the cost of rendering over again, but after that it becomes memoized, ready for the next re-render of MainComponent. Am I correct to say, while b is not updated during this render cycle, the <p>This is the string of {b}</p> (not memoized) is re-rendered, paying the cost of rendering?






Am I using React's memo correctly? Which of these alternatives would be better? Are they functionally the same?



  1. React.memo


const AComponent = React.memo(props => <p>This is the string of {props.a}</p>)


  1. React.useMemo


const aComponent = React.useMemo(() => <p>This is the string of {a}</>, [a])

// then use it like
return <>{ aComponent }</>

More From » reactjs

 Answers
2

a) Memoizing is always faster in my tests (despite some blog posts saying otherwise). Having said that you're not going to see any noticeable gains unless you have a particularly heavy component, or the component is rendering lots of children. It could also save you from loosing focus if you're typing and that input gets re-rendered because the parent does.


b) In short none of them will work, React.memo has to sit outside the render function, it's not part of the "magic" use hook functions which maintain references. You have to use useMemo for inside render. Here's an example: The components which don't re-render every second are CComponent and DComponent:




const CComponent = React.memo(({ count }) => (
<p>Not re-rendered every second: {count}</p>
));

const MainComponent = (props) => {
const AComponent = React.memo(() => (
<p>Re-render when parent does: {props.count}</p>
));

const BComponent = React.memo(({ count }) => (
<p>Re-render when parent does: {count}</p>
));

const DComponent = React.useMemo(() => (
<p>Not re-rendered every second: {props.count}</p>
), [props.count]);

return (
<div>
<AComponent />
<BComponent count={props.count} />
<CComponent count={props.count} />
{DComponent}
<p>parent count: {props.count}</p>
<p>parent anotherCounter: {props.anotherCounter}</p>
</div>
);
};

function App() {
const [count, setCount] = React.useState(0);
const [anotherCounter, setAnotherCounter] = React.useState(100);

React.useEffect(() => {
const h = setInterval(() => {
setCount((c) => c + 1);
}, 6000);
const h2 = setInterval(() => {
setAnotherCounter((c) => c + 1);
}, 1000);
return () => {
clearInterval(h);
clearInterval(h2);
};
}, []);

return (
<div className=App>
<MainComponent count={count} anotherCounter={anotherCounter} />
</div>
);
}


ReactDOM.render(<App />, document.querySelector('#container'));

<script src=https://unpkg.com/react@17/umd/react.production.min.js></script>
<script src=https://unpkg.com/react-dom@17/umd/react-dom.production.min.js></script>
<div id=container></div>




[#1866] Monday, January 25, 2021, 3 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
keric

Total Points: 572
Total Questions: 93
Total Answers: 97

Location: Cyprus
Member since Mon, Oct 24, 2022
2 Years ago
keric questions
Thu, Dec 2, 21, 00:00, 3 Years ago
Mon, Jul 19, 21, 00:00, 3 Years ago
Thu, Jul 15, 21, 00:00, 3 Years ago
Thu, Nov 5, 20, 00:00, 4 Years ago
Sat, Jul 11, 20, 00:00, 4 Years ago
;