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")
);Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
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()}</>.
意想不到的部分来了,当我隐藏(单击按钮)并再次显示两个记忆组件时,它们的行为有所不同。第一个将始终显示与第一次初始化时获得的相同的随机数。而秒一会重新初始化每次。
从截图中可以看出,第一个组件的随机数保持不变,而第二个则没有。
有趣的是,如果我使用计数器而不是显示/隐藏,它确实会被记住:
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")
);Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
这是一个自己尝试的代码笔https://codepen.io/brandiatmuhkuh/pen/eYWmyWz
\n\n为什么它现在的表现是这样的?
\n
<Rand />不调用您的组件函数。它只是调用React.createElement创建 React 元素(而不是它的实例)。您的组件函数用于在您使用它时呈现元素实例。在您的“工作”示例中,您正在执行以下操作:
<>{Math.random()}</>\nRun Code Online (Sandbox Code Playgroud)\n...它在Math.random片段中调用并使用其结果作为文本(而不是组件)。
但你的“不工作”的例子就是这样:
\n<Rand />\nRun Code Online (Sandbox Code Playgroud)\n该元素已创建,但未使用,并且您的函数未调用。“你的函数没有被调用”部分可能会令人惊讶\xc2\xa0\xe2\x80\x94,当我开始使用 React\xc2\xa0\xe2\x80\x94 时,这对我来说是令人惊讶的,但这是真的:
\n<>{Math.random()}</>\nRun Code Online (Sandbox Code Playgroud)\r\n<Rand />\nRun Code Online (Sandbox Code Playgroud)\r\n\n\n在这两种情况下如何防止重新渲染/重新初始化组件?
\n
如果您执行示例中所做的操作,即将挂载的组件完全从树中取出,那么您将卸载该组件实例;当你把它放回去时,你的函数将被再次调用,所以你将得到一个新值。(这也是带有计数器的版本没有表现出此行为的原因:组件实例保持安装状态。)
\n如果你想记住它显示的内容,一种方法是将其作为道具传递给它,并记住你传递给它的内容:
\nconst { Fragment } = React;\n\nfunction Rand() {\n console.log("Rand called");\n return <Fragment>{Math.random()}</Fragment>;\n}\n\nconsole.log("before");\nconst element = <Rand />;\nconsole.log("after");\n\n// Wait a moment before *using* it\nsetTimeout(() => {\n ReactDOM.render(\n element,\n document.getElementById("root")\n );\n}, 1000);Run Code Online (Sandbox Code Playgroud)\r\n<div id="root"></div>\n\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>Run Code Online (Sandbox Code Playgroud)\r\n| 归档时间: |
|
| 查看次数: |
60 次 |
| 最近记录: |