我最近正在学习React的
useEffect
钩子,我尝试用useState
和useEffect
编写一个函数来看看不同类型的useEffect
依赖是如何工作的。下面是我的代码:
import { useEffect, useState } from "react";
import "./App.css";
function App() {
const [st1, setSt1] = useState("");
const [st2, setSt2] = useState("");
console.log("I'm in...");
useEffect(() => {
console.log("ef1");
});
useEffect(() => {
console.log("ef2");
setSt1("st1");
}, []);
useEffect(() => {
console.log("ef3");
setSt2("st2");
}, [st1]);
useEffect(() => {
console.log("ef4");
}, [st1, st2]);
return (
<div className="App">
<header className="App-header"></header>
</div>
);
}
export default App;
在我的预期中,第一次会运行每个
useEffect
设置功能,然后setState
会导致重新渲染并运行ef1
、ef3
、ef4
,然后是ef3
setState
会导致最后一次重新渲染并运行ef1
。所以我的预期输出是
I'm in...
ef1
ef2
ef3
ef4
I'm in...
ef1
// check st1, different, execute ef3
ef3
// check st2, different, execute ef4
ef4
I'm in...
ef1
// check st2, same as previous value, doing nothing
但是当我运行代码时,真正的输出是
I'm in...
ef1
ef2
ef3
ef4
I'm in...
ef1
ef3
ef4
I'm in...
我不明白为什么它在上次渲染中不执行
ef1
函数。
有人可以向我解释一下吗?谢谢
第一次渲染后,所有效果都将被执行,给出:
I'm in...
ef1
ef2
ef3
ef4
React 将批处理 useEffects 中发生的状态更新,因此当 React 第二次重新渲染并执行组件时,
st1
和 st2
现在都将在其中包含更新后的值。由于 st1
和 st2
都已更改,您的第三个和第四个效果将运行(以及第一个效果,因为未提供依赖项),给出:
I'm in...
ef1
ef3
ef4
第三个效果中的状态更新不会更改状态,因此我们应该完成所有日志记录。但是,当您使用相同的值调用 set state 挂钩时,React 将bail out下一个“渲染”,并且 React 可能需要在退出之前额外渲染您的组件一段时间(以检查渲染输出)没有改变)。当 React 第三次调用你的组件时,你会得到:
I'm in...
在这种情况下,React 调用了您的组件,但没有提交任何内容,因为没有任何更改,因此不会运行任何效果。从上面关于救助的文档链接:
React 将退出,而不会渲染孩子或发射效果
救助/“额外”重新渲染细节是一个实现细节,通常你不需要担心它,因为你的 React 组件应该是纯粹的,但是,如果你愿意,你可以阅读更多关于丹·阿布拉莫夫(Dan Abramov)的这个答案,他的这个帖子,或者这个其他答案中的救助行为的更多信息,或者这篇文章。
那是因为依赖数组等于
useEffect
的 undefined
将在每次重新渲染时运行。基本上,当您执行 setState
时,您会触发突变(例如重新渲染)。自:
useEffect(() => {
console.log("ef2");
setSt1("st1");
}, []); // runs only on first render
useEffect(() => {
console.log("ef3");
setSt2("st2");
}, [st1]); // runs only on second render
useEffect(() => {
console.log("ef4");
}, [st1, st2]); // runs on every renderer, but does not perform mutation
在第三次渲染时,您不会触发
ef4
中的任何突变,因此您的 ef1
使用效果不会被触发。