组件是不是渲染了两次?是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
为什么在useEffect中id
等于1?
好像组件已经渲染了两次,但是为什么第二次没有调用 useMemo 和 useEffect 呢? 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问题吗?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 React 组件中调用了两次 Promise.then 而不是 console.log?