为什么在这里反应console.log 3次

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

让我们看看这段代码:
应用程序.tsx

import "./App.css";
import useHome from './hooks/useHome';

function App() {
  useHome();
  return <></>;
}

export default App;

钩子/useHome.ts

import { useEffect, useState } from "react";

const query = (): Promise<number> =>
  new Promise((resolve) =>
    setTimeout(() => {
      resolve(1);
    }, 1000),
  );

const useHome = () => {
  const [pageStatus, setPageStatus] = useState<string>("loading");
  const [data, setData] = useState<number | null>(null);
  const [deps, setDeps] = useState(data);

  const queryData = async () => {
    setPageStatus("loading");
    try {
      const pageData = await query();
      setData(pageData); // cause second render
      setPageStatus("normal"); // cause third render
    } catch (e) {
      setPageStatus("error");
    }
  };

  useEffect(() => {
    queryData(); 
  }, []);

  useEffect(() => {
    setDeps(data); // cause third render 
  }, [data]);

  console.log("@render"); // total 3 times

  return {
    deps,
    data,
    pageStatus,
  };
};

export default useHome;

为什么'@render'只console.log 3次?
我预计它会渲染 4 次;
首先在初始化时渲染,
由于 setData
渲染第二个 由于 setPageStatues 而渲染第三个(这里是异步函数环境)
由于 setDeps
导致渲染 但我发现它只控制台3次...
React 是否合并了 setPageStatues 和 setDeps ?

reactjs
3个回答
0
投票

每次重新渲染组件时,控制台日志都会触发。 (即每次组件状态发生变化时)

此外,最初的反应会在开发模式下渲染你的组件两次,但它只会在本地执行,而不是在生产版本中执行。


0
投票
setData(pageData); // cause second render
setPageStatus("normal"); // cause third render

你的假设是错误的。这些不会导致重新渲染。这些队列/批处理各自的状态更新。操作完成后,将执行状态更新并重新渲染组件。


0
投票
React的批量更新机制

    初始渲染:
  1. 当你的组件App挂载时,它会触发useHome钩子。此时,@render 会记录一次。
  2. 通过useEffect触发queryData:
  3. 在queryData内部,首先将pageStatus设置为“loading”,这会将状态更新排队。(不是立即执行,只是将其排队) 然后等待 query() ,它会在 1 秒后解析。 query() 解析后,调用 setData,对另一个状态更新进行排队。 设置数据后,立即将 pageStatus 设置为“正常”,从而对另一个状态更新进行排队。 因此,在这种情况下,React 会智能地将这些更新批处理到单个渲染周期中。因此,这些更改只会导致一次渲染,而不是单独的渲染。
  4. 最终(第三次渲染)
  5. 由 setDeps 引起,正如您已经提到的。
© www.soinside.com 2019 - 2024. All rights reserved.