我想弄清楚,何时useEffect导致重新渲染。以下示例的结果使我感到非常惊讶:
https://codesandbox.io/embed/romantic-sun-j5i4m
function useCounter(arr = [1, 2, 3]) {
const [counter, setCount] = useState(0);
useEffect(() => {
for (const i of arr) {
setCount(i);
console.log(counter);
}
}, [arr]);
}
function App() {
useCounter();
console.log("render");
return <div className="App" />;
}
该示例的结果如下:
我的困惑来自两件事:我不知道为什么:
如果有人能澄清我将非常高兴。谢谢!
最佳答案
我将尽力解释(或逐步进行)正在发生的事情。我还在第7点和第10点做两个假设。
useEffect
。 useEffect
将“保存”初始状态,因此,只要在内部引用,counter
将为0。 setCount
都被调用以更新计数,并且控制台日志记录根据“存储”版本为0的计数器。因此,数字0在控制台中记录了3次。因为状态已更改(0-> 1、1-> 2、2-> 3),所以React集就像一个标志或一些要告诉自己要记住要重新渲染的东西。 useEffect
时未重新渲染任何内容,而是等待useEffect
完成后重新渲染。 useEffect
后,React会记住counter
的状态在其执行过程中已更改,因此它将重新呈现该应用程序。 useCounter
。请注意,这里没有参数传递给useCounter
自定义钩子(Hook)。假设:我自己也不知道,但是我认为默认参数似乎是重新创建的,或者至少以某种方式使React认为它是新的。因此,由于
arr
被视为新的,因此useEffect
挂钩将再次运行。这是我可以解释第二次运行的useEffect
的唯一原因。 useEffect
期间,counter
的值为3。控制台日志将按预期方式记录3的数字3。 useEffect
后,React发现计数器在执行过程中发生了变化(3-> 1,1-> 2,2-> 3),因此该应用将重新渲染,从而导致第三个“渲染”日志。 useCounter
挂钩的内部状态在此渲染与前一个渲染之间没有变化,因此它不执行其中的代码,因此第三次不调用useEffect
。因此,应用程序的第一个渲染将始终运行挂钩代码。应用程序第二次看到钩子(Hook)的内部状态从0变为3,因此决定重新运行它,第三次应用程序看到钩子(Hook)的内部状态为3仍然为3,因此决定不执行该操作。重新运行它。这是我可以提出的使钩子(Hook)不再运行的最好原因。您可以在挂钩本身中放入日志,以查看它实际上并没有第三次运行。 这就是我所看到的,我希望这可以使它更加清晰。