考虑以下 React 中的虚拟代码:
import { useEffect, useState } from "react";
const Welcome = () => {
console.log("[Welcome] rendered");
return <h1>Hello World</h1>;
};
const App = () => {
console.log("[App] rendered");
const [myState, setMyState] = useState(false);
useEffect(() => {
console.log("[App - useEffect] Callback");
setMyState(true);
});
return <Welcome />;
};
export default App;
当我运行这个应用程序时控制台上的输出是:
[App] rendered
[Welcome] rendered
[App - useEffect] Callback
[App] rendered
[Welcome] rendered
[App - useEffect] Callback
[App] rendered
第一个问题:
当没有状态更改时,为什么在控制台上第三次打印打印 [App] rendered
的最后一条消息(myState
是 true
并再次设置为 true
)?如果再次渲染 App
组件,为什么在它之后不打印 [Welcome] rendered
?
问题说明:
当我运行应用程序时,App
组件首次在控制台上呈现消息 [App] rendered
。由于 App
组件将 Welcome
作为其子组件,因此消息 [Welcome] rendered
打印在控制台上,子组件 Welcome
安装在 DOM 上,从而安装了 {{1}也是组件。一旦 App
组件安装在 DOM 上,App
钩子内的回调函数就会被执行并在控制台上打印 useEffect
。此回调函数中的下一条语句将 [App - useEffect] Callback
状态变量设置为 myState
(之前为 true
)。因为 false
组件的状态发生了变化,它会被重新渲染。这会在控制台上打印另一个 App
语句。要呈现 [App] rendered
,需要呈现 App
组件,该组件在控制台上打印 Welcome
。一旦 [Welcome] rendered
组件被完全呈现(或评估),控件就会转到 App
钩子并且语句 useEffect
再次打印在控制台上。这一次,我再次将状态变量 [useEffect] Callback
设置为 myState
(之前也是 true
),从而不会改变上一次渲染的状态,因此没有重新渲染true
组件。因此,我不应该在控制台上看到第三个 App
消息。
第二个疑问:
对于我的第二个疑问,请考虑下面给出的稍微更改的代码(将 [App] rendered
设置为 myState
,而不是之前将其设置为 false
):
true
当我运行这个稍微修改过的应用程序时,控制台上的输出是:
import { useEffect, useState } from "react";
const Welcome = () => {
console.log("[Welcome] rendered");
return <h1>Hello World</h1>;
};
const App = () => {
console.log("[App] rendered");
const [myState, setMyState] = useState(false);
useEffect(() => {
console.log("[App - useEffect] Callback");
setMyState(false);
});
return <Welcome />;
};
export default App;
如果在前面的代码中第三次打印了 [App] rendered
[Welcome] rendered
[App - useEffect] Callback
,那么为什么消息 [App] rendered
没有在此处第二次被记录?为什么两个代码片段的结果不一致?
附言
虚拟代码保持微不足道,因此我可以更多地关注概念而不是代码,并且我故意不在 [App] rendered
中使用任何依赖数组。