gpt4 book ai didi

reactjs - useMemo 内联组件与普通组件的行为不同

转载 作者:行者123 更新时间:2023-12-04 11:35:06 24 4
gpt4 key购买 nike

我有以下 react 代码

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>

它使用 useMemo 2次。
第一次使用内联组件“初始化”并记住组件( const working = useMemo(() => <>{Math.random()}</>, []); )
第二次使用在 app 组件之外制作的组件 ( const notWorking = useMemo(() => <Rand />, []); ) useMemo 中使用的两个组件函数具有完全相同的代码,即 <>{Math.random()}</> .
意想不到的部分来了,当我隐藏(单击按钮)并再次显示两个内存组件时,它们的行为有所不同。第一个将始终显示与第一次初始化时获得的相同的随机数。而秒一会重新初始化每次。
第一次渲染
enter image description here
第二次渲染(隐藏)
enter image description here
第三次渲染(再次显示)
enter image description here
从截图中可以看出,第一个组件的随机数保持不变,而第二个则没有。
我的问题:
  • 在这两种情况下,如何防止重新渲染/重新初始化组件?
  • 为什么它目前的行为如此?

  • 有趣的是,如果我使用计数器而不是显示/隐藏,它确实会被记住:

    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>

    这里有一个codepen可以自己试试 https://codepen.io/brandiatmuhkuh/pen/eYWmyWz

    最佳答案

    Why does it currently behave as it does?

    <Rand />不会调用您的组件函数。它只是调用 React.createElement创建 React 元素(不是它的实例)。您的组件函数用于渲染元素实例,如果您使用它以及何时使用它。在您的“工作”示例中,您正在执行以下操作:
    <>{Math.random()}</>
    ...调用 Math.random并将其结果用作片段中的文本(不是组件)。
    但是您的“不工作”示例只是:
    <Rand />
    该元素已创建,但未使用,并且未调用您的函数。 “你的函数没有被调用”部分可能令人惊讶——当我开始使用 React 时,这对我来说是——但这是真的:

    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?


    如果您在示例中执行了您在示例中所做的操作,即将挂载的组件完全从树中取出,那么您就是在卸载组件实例;当你把它放回去时,你的函数 再次被调用,所以你会得到一个新的值。 (这也是为什么带有计数器的版本没有表现出这种行为:组件实例保持挂载。)
    如果你想记住它显示的内容,一种方法是将它作为 Prop 传递给它,并记住你传递的内容:

    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>

    关于reactjs - useMemo 内联组件与普通组件的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68195167/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com