nop*_*ole 6 javascript reactjs codesandbox react-hooks
以下代码在 codeandbox.io 网站的控制台(该版本使用StrictMode)以及下面的代码段(未使用StrictMode)中打印出相同的时间两次:
const { useState, useEffect } = React;
function useCurrentTime() {
const [timeString, setTimeString] = useState("");
useEffect(() => {
const intervalID = setInterval(() => {
setTimeString(new Date().toLocaleTimeString());
}, 100);
return () => clearInterval(intervalID);
}, []);
return timeString;
}
function App() {
const s = useCurrentTime();
console.log(s);
return <div className="App">{s}</div>;
}
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.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.development.js"></script>Run Code Online (Sandbox Code Playgroud)
演示:https : //codesandbox.io/s/gallant-bas-3lq5w?file=/ src/ App.js(使用StrictMode)
这是使用生产库的片段;它仍然记录两次:
const { useState, useEffect } = React;
function useCurrentTime() {
const [timeString, setTimeString] = useState("");
useEffect(() => {
const intervalID = setInterval(() => {
setTimeString(new Date().toLocaleTimeString());
}, 100);
return () => clearInterval(intervalID);
}, []);
return timeString;
}
function App() {
const s = useCurrentTime();
console.log(s);
return <div className="App">{s}</div>;
}
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.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>Run Code Online (Sandbox Code Playgroud)
然而,当我打开开发者控制台时,我看到每次只打印一次,而且在 codeandbox.io 的控制台中,我看到它打印了一次。
然后如果我使用 create-react-app 创建一个独立的 React 应用程序,并使用上面的代码,并且每次都打印两次。
如何理解这种行为,根据不同情况打印一次或两次?我的想法是,如果状态发生变化,则App使用新字符串重新渲染一次,因此它会打印一次。特别奇怪的是为什么它打印了两次,但是当 Dev Console 打开时,它是一次?
据我所知,我们看到的双重调用App是预期的行为。从useState文档中:
\n\n摆脱状态更新
\n如果将 State Hook 更新为与当前状态相同的值,React 将退出而不渲染子项或触发效果。(React 使用
\nObject.is比较算法。)请注意,React 可能仍需要在退出之前再次渲染该特定组件。这不应该成为一个问题,因为 React 不会不必要地将 \xe2\x80\x9cdeeper\xe2\x80\x9d 放入树中。如果您\xe2\x80\x99在渲染时进行昂贵的计算,您可以使用
\nuseMemo.
其中的关键位是“请注意,React 可能仍需要在退出之前再次渲染该特定组件...”和“...React won\xe2\x80\x99t 不必要地转到 \xe2\x80\x9cdeeper\xe2\x80 \x9d 进入树中...”
\n事实上,如果我更新您的示例,以便它使用子组件来显示时间字符串,我们只会看到每个值调用子组件一次timeString,而不是按原样调用两次App,即使子组件没有包装在React.memo:
const { useState, useEffect } = React;\n\nfunction useCurrentTime() {\n const [timeString, setTimeString] = useState("");\n \n useEffect(() => {\n const intervalID = setInterval(() => {\n setTimeString(new Date().toLocaleTimeString());\n }, 100);\n return () => clearInterval(intervalID);\n }, []);\n \n return timeString;\n}\n\nfunction ShowTime({timeString}) {\n console.log("ShowTime", timeString);\n return <div className="App">{timeString}</div>;\n}\n\nfunction App() {\n const s = useCurrentTime();\n console.log("App", s);\n \n return <ShowTime timeString={s} />;\n}\n\nReactDOM.render(<App />, document.getElementById("root"));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.1/umd/react.production.min.js"></script>\n<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>Run Code Online (Sandbox Code Playgroud)\r\n当我运行它时,我看到:
\nApp 09:57:14\nShowTime 09:57:14\nApp 09:57:14\nApp 09:57:15\nShowTime 09:57:15\nApp 09:57:15\nApp 09:57:16\nShowTime 09:57:16\nApp 09:57:16\nApp 09:57:17\nShowTime 09:57:17\nApp 09:57:17\nApp 09:57:18\nShowTime 09:57:18\nApp 09:57:18\nApp 09:57:19\nShowTime 09:57:19\nApp 09:57:19\nApp 09:57:20\nShowTime 09:57:20\nApp 09:57:20\nRun Code Online (Sandbox Code Playgroud)\n请注意,虽然App的每个值被调用两次timeString,ShowTime但仅被调用一次。
我应该指出,这比class组件更自动化。class如果您没有实现,等效组件将每秒更新 10 次shouldComponentUpdate。:-)
您在 CodeSandbox 上看到的一些内容很可能是由于此处StrictMode的原因造成的。但是对每个值的两次调用只是 React 在做它的事情。ApptimeString
| 归档时间: |
|
| 查看次数: |
111 次 |
| 最近记录: |