I have the following React code
const { useState, useMemo, Fragment } = React;
function Rand() {
return <Fragment>{Math.random()}</Fragment>;
}
const App = () => {
const [show, setShow] = useState(true);
// The inline component gets memoized. But <Rand /> does not
const working = useMemo(() => <Fragment>{Math.random()}</Fragment>, []);
// The rand component is not memoized and gets rerendred
const notWorking = useMemo(() => <Rand />, []);
return(
<Fragment>
<button
onClick={() => {
setShow(!show);
}}>
{show?"Hide":"Show"}
</button>
<br />
Working:
{show && working}
<br />
Not Working:
{show && notWorking}
</Fragment>
);
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
It uses useMemo 2 times.
The first time it uses an inline component to "initialize" and memoize a component ( const working = useMemo(() => <>{Math.random()}</>, []);)
The second time it uses a component which was made outside the app component (const notWorking = useMemo(() => <Rand />, []);)
Both components used in the useMemo function have the exact same code, which is <>{Math.random()}</>.
Here comes the unexpected part, when I hide (Click the button) and show the two memoized components again, they behave differently. The first one will always show the same random number which it got when it first got initialzied. While the seconds one will re-initialize each time.
First render
Second render (hide)
Third render (show again)
You can see from the screenshots that the first component's random number stays the same, while the second one does not.
My Questions:
- How can I prevent in both cases to re-render/re-initialize the component?
- Why does it currently behave as it does?
Interestingly, it does get memoized if I use a counter instead of show/hide:
const { useState, useMemo, Fragment } = React;
function Rand() {
return <Fragment>{Math.random()}</Fragment>;
}
const App = () => {
const [counter, setCounter] = useState(0);
// The inline component gets memoized. But <Rand /> does not
const working = useMemo(() => <Fragment>{Math.random()}</Fragment>, []);
// The rand component is not memoized and gets rerendred
const notWorking = useMemo(() => <Rand />, []);
return(
<Fragment>
<button
onClick={() => {
setCounter(c => c + 1);
}}>
Update ({counter})
</button>
<br />
Working:
{working}
<br />
Not Working:
{notWorking}
<br />
<code>Rand</code> used directly:
<Rand />
</Fragment>
);
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
Here is a codepen to try it yourself https://codepen.io/brandiatmuhkuh/pen/eYWmyWz


