组件是不是渲染了两次?是codeandbox问题吗?

Posted

技术标签:

【中文标题】组件是不是渲染了两次?是codeandbox问题吗?【英文标题】:Is component rendered twice? Is it codesandbox problem?组件是否渲染了两次?是codeandbox问题吗? 【发布时间】:2021-09-26 09:36:58 【问题描述】:

这是我的简单 React 应用程序:

let idCounter = 0;

export default function App() 
  const id = useMemo(() => 
    console.log("useMemo");
    return idCounter++;
  , []);

  console.log("render", id);

  useEffect(() => 
    console.log("useEffect", id);
  );

  return id;

https://codesandbox.io/s/morning-bush-swky8

这是控制台输出:

useMemo
render 0
useEffect 1

为什么在useEffectid等于1

好像组件已经渲染了两次,但是为什么第二次没有调用 useMemouseEffect 呢? id 是如何变成 1 的?

【问题讨论】:

我不知道从哪里开始,因为有很多事情完全违背了您应该如何编写 React 功能组件。 setTimeout 之类的东西不应该从主要组件体内调用(它应该在 useEffect 函数中),同样你的 useMemo 在这里没有意义,因为它是一种记忆值的方式,并且函数应该是side-无效果-我不知道您要通过在其中递增来实现什么。但我并不惊讶通过做奇怪的事情你会得到奇怪的结果! @RobinZigmond 此代码仅用于测试目的!不要怪我在渲染阶段使用 setTimeout 等等。 @RobinZigmond 我删除了 setTimeout。但是现在你得到的调试信息更少了。 @J.Snow 我不认为 RobinZigmond 的意思是责备你,只是注意到,React 对这些小事很敏感,并且偏离了“最佳实践”可以使它产生奇怪的结果,可能包括您所询问的结果。别生气,我们讨论的是一些代码,而不是你的编码风格。 【参考方案1】:

来自React Docs - Strict Mode:

从 React 17 开始,React 自动修改控制台 像 console.log() 这样的方法在第二次调用中使日志静音 生命周期函数。但是,它可能会导致不良行为 在某些情况下可以使用变通方法。

您的组件确实被渲染了两次,但在 StrictMode 引起的第二次重新渲染期间,React 隐藏了日志语句。

如果您删除StrictMode,您将获得预期的输出。

另一种选择是在console 对象上使用不同的方法进行日志记录,例如console.dir

let idCounter = 0;

function App() 
  const id = React.useMemo(() => 
    console.dir("useMemo");
    return idCounter++;
  , []);

  console.dir("render");
  console.dir(id);

  React.useEffect(() => 
    console.log("useEffect", id);
  );

  return id;


ReactDOM.render(
  <React.StrictMode>
    <App/>
  </React.StrictMode>, 
  document.querySelector("#root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.min.js"></script>

<div id="root"></div>

【讨论】:

太棒了!正是我想要的!

以上是关于组件是不是渲染了两次?是codeandbox问题吗?的主要内容,如果未能解决你的问题,请参考以下文章

构造函数和渲染方法在反应组件中运行两次

在页面重载时,我的Gatsby.js页脚组件渲染了两次。

为啥在 React 组件中调用了两次 Promise.then 而不是 console.log?

从组件中的 useState 多次调用 state updater 会导致多次重新渲染

反应:类中的所有方法都运行 2 次

React 组件有时会在状态不变的情况下渲染两次