score:2

Why does it currently behave as it does?

<Rand /> doesn't call your component function. It just calls React.createElement to create the React element (not an instance of it). Your component function is used to render an element instance, if and when you use it. In your "working" example you're doing:

<>{Math.random()}</>

...which calls Math.random and uses its result as text (not a component) within the fragment.

But your "not working" example just does:

<Rand />

The element is created, but not used, and your function isn't called. The "your function isn't called" part may be surprising — it was to me when I started using React — but it's true:

const { Fragment } = React;

function Rand() {
    console.log("Rand called");
    return <Fragment>{Math.random()}</Fragment>;
}

console.log("before");
const element = <Rand />;
console.log("after");

// Wait a moment before *using* it
setTimeout(() => {
    ReactDOM.render(
        element,
        document.getElementById("root")
    );
}, 1000);
<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>

How can I prevent in both cases to re-render/re-initialize the component?

If you do what you've done in your example, which is to take the mounted component out of the tree entirely, you're unmounting the component instance; when you put it back, your function will get called again, so you'll get a new value. (This is also why the version with the counter doesn't exhibit this behavior: the component instance remained mounted.)

If you want to memoize what it shows, one approach is to pass that to it as a prop, and memoize what you pass it:

const { useState, useMemo, Fragment } = React;

function Rand({text}) {
    return <Fragment>{text}</Fragment>;
}

const App = () => {
    const [show, setShow] = useState(true);
    
    const working = useMemo(() => <Fragment>{Math.random()}</Fragment>, []);
    const randText = useMemo(() => String(Math.random()), []);

    return(
        <Fragment>
            <button
                onClick={() => {
                  setShow(!show);
                }}>
                {show?"Hide":"Show"}
            </button>
            <br />
            Working: 
            {show && working}
            <br />
            Also Working Now: 
            {show && <Rand text={randText} />}
        </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>


Related Query

More Query from same tag