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:
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?
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?
const AComponent = React.memo(props => <p>This is the string of {props.a}</p>)
const aComponent = React.useMemo(() => <p>This is the string of {a}</>, [a])
// then use it like
return <>{ aComponent }</>
I used the memo in a little experiment, I upload the pictures maybe it will be useful.
Title.js:
App.js:
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>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.