如果不设置依赖项,useEffect设置函数每次重新渲染时都会运行吗?

问题描述 投票:0回答:2

我最近正在学习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
函数。 有人可以向我解释一下吗?谢谢

reactjs react-hooks
2个回答
2
投票

第一次渲染后,所有效果都将被执行,给出:

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)的这个答案,他的这个帖子,或者这个其他答案中的救助行为的更多信息,或者这篇文章


2
投票

那是因为依赖数组等于

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
使用效果不会被触发。

© www.soinside.com 2019 - 2024. All rights reserved.