以下代码同时在codesandbox.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"));<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>
演示: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"));<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>
但是,当我打开开发人员的控制台时,每次只打印一次,而且在codesandbox.io的控制台中,我看到它打印了一次。
然后如果我用创建一个独立的React,并使用上面的代码,每次打印两次。
如何理解这种行为,根据不同的情况打印一次或两次?我的想法是,如果状态改变了,那么App就会被重新呈现,使用新的字符串 once ,所以它被打印了一次。奇怪的是,为什么它要打印两次,但是当Dev控制台打开时,它就只打印了一次?
发布于 2021-03-08 10:01:52
据我所知,我们看到的对App的双重调用是预期的行为。来自useState documentation
退出状态更新
如果您将状态挂钩更新为与当前状态相同的值,则React将在不呈现子状态或触发效果的情况下退出。(React使用Object.is比较算法。)
注意,在退出之前,React可能仍然需要再次呈现特定的组件。这不应该是一个问题,因为反应不会不必要地“深入”到树上。如果您在渲染时进行昂贵的计算,则可以使用useMemo优化它们。
其中的关键部分是“在退出之前,可能仍然需要重新呈现特定的组件.”而且"...React不会不必要地“深入到树上.”
实际上,如果我更新您的示例,以便它使用一个子组件来显示时间字符串,那么我们只看到该子组件在每个值中调用一次,而不是App值的两倍,即使子组件没有包装在React.memo中。
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 ShowTime({timeString}) {
console.log("ShowTime", timeString);
return <div className="App">{timeString}</div>;
}
function App() {
const s = useCurrentTime();
console.log("App", s);
return <ShowTime timeString={s} />;
}
ReactDOM.render(<App />, document.getElementById("root"));<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>
当我运行它时,我看到:
App 09:57:14
ShowTime 09:57:14
App 09:57:14
App 09:57:15
ShowTime 09:57:15
App 09:57:15
App 09:57:16
ShowTime 09:57:16
App 09:57:16
App 09:57:17
ShowTime 09:57:17
App 09:57:17
App 09:57:18
ShowTime 09:57:18
App 09:57:18
App 09:57:19
ShowTime 09:57:19
App 09:57:19
App 09:57:20
ShowTime 09:57:20
App 09:57:20注意,尽管App对timeString的每个值调用了两次,但ShowTime只被调用了一次。
我应该注意到,这比使用class组件更加自动化。如果不实现class,等效的shouldComponentUpdate组件将每秒更新10次。:-)
您在CodeSandbox上看到的部分内容很可能是由于StrictMode,更多是关于here的。但是,对每个App值的两个timeString调用只是在做它的事情。
https://stackoverflow.com/questions/66525901
复制相似问题