我的 React 组件由于严格模式而渲染两次。

225

我的React组件渲染两次。因此,我决定逐行调试,问题出在这里:

 if ( workInProgress.mode & StrictMode) {
        instance.render();
      }

React-dom.development.js

是因为严格模式吗?我可以禁用它吗?什么是严格模式?我需要它吗?

2
应该将 StrictMode 视为最后的解决方案。更详细的答案请参见 https://dev59.com/OlEG5IYBdhLWcg3wJlLh。 - Youssouf Oumar
8
这是来自React文档的答案(来源:我写的)。我希望它能排名更高。https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development - Dan Abramov
6个回答

661

为了检测代码问题并提醒您(这可能非常有用),StrictMode在dev(但不是production)中会呈现组件两次。

如果您在应用程序中启用了StrictMode但不记得启用它,可能是因为您最初使用create-react-app或类似工具创建了应用程序,该工具会自动默认启用StrictMode。

例如,您可能会发现您的{app}被包装在<React.StrictMode>中,在index.js中:

  ReactDOM.render(
     <React.StrictMode>
       {app}
     </React.StrictMode>,
    document.getElementById('root')
  );

如果是这样,您可以通过删除<React.StrictMode>标签来禁用StrictMode:

  ReactDOM.render(
    {app}
    document.getElementById('root')
  );

21
在开发模式下,文档提到了有意的“双重调用”:“严格模式不能自动检测到副作用,但它可以通过使副作用更加确定性来帮助您发现它们。这是通过有意地双重调用以下函数来实现的。” - Nick Mitchell
1
事件监听器被调用两次,一直在想原因。似乎是严格模式引起的。谢谢! - Jakub Kvba
15
对于Next.js开发者来说,可以在next.config.js文件中设置"reactStrictMode: false"来禁用它。 - Mahmoud
8
StrictMode 应该作为最后的解决方案来移除。更详细的答案请参见 https://dev59.com/OlEG5IYBdhLWcg3wJlLh。 - Youssouf Oumar
4
以下是React文档的相关部分:https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development - Dan Abramov
显示剩余4条评论

42

是的,你需要移除Strict模式,因为

Strict模式无法自动检测副作用,但它可以通过使副作用更加确定性来帮助你发现它们。这是通过有意双重调用以下函数来实现的:类组件构造函数、render方法和shouldComponentUpdate方法。

来源:React文档:Strict Mode


10
若我可以补充一点,如果你保持它开启,它将帮助你编写更具弹性的组件并帮助你更早地发现错误。所以并不是你必须要使用它,但强烈建议你使用。请注意,双重渲染仅会在开发时发生,不会出现在生产环境中。 - Jackyef
1
@Jackyef我该如何移除它?或者将我的应用程序放入生产模式?<React></React> 报错了。 - Marry Joanna
4
只需移除包裹在你的应用程序上方的<React.StrictMode>,问题就会解决。 - Jackyef
1
你在{app}后面漏掉了逗号,应该写成这样:{app}, - kimilhee
2
应该将 StrictMode 视为最后的解决方案。更详细的答案请参见 https://dev59.com/OlEG5IYBdhLWcg3wJlLh。 - Youssouf Oumar

30

对于像我这样使用Next.js的用户,严格模式也已默认启用并引起了此问题。

您可以通过以下方式禁用它

// next.config.js
module.exports = {
  reactStrictMode: false,
}

你是对的,它默认为true,将reactStrictMode设置为false可以解决问题,但我们也应该记住,正如nextjs文档建议的那样,保持reactStrictMode为true也可能是有益的:https://nextjs.org/docs/api-reference/next.config.js/react-strict-mode - Elyas Karimi
StrictMode存在有其重要的原因,禁用它是最后的选择。如需更详细的答案,请参见https://dev59.com/OlEG5IYBdhLWcg3wJlLh#72238236。 - Youssouf Oumar

9
在使用StrictMode的React应用程序中:
  • 如果您看到如下所示的双重控制台日志: Dual console logs image

  • 并且您知道StrictMode可以帮助您以某种方式优化应用程序

  • 而您又不想完全禁用StrictMode

那么:

React Developer Tools Chrome Extension提供了一个选项,可以在StrictMode下隐藏第二次渲染期间的日志。要启用此选项:

  • 安装扩展程序。
  • 在您的 Chrome 开发者工具窗口中,将会创建一个名为 Components 的新标签页。单击它。 Components tab image
  • 然后单击组件选项卡内的齿轮图标。 Components gear icon image
  • 接着选择 Debugging 选项卡,并勾选 Hide logs during second render in Strict Mode 选项。 Debugging tab image

您将不再在控制台中看到双重日志。 No dual console logs image


2
很不幸地,我仍然看得到。甚至在重新打开标签后也一样。 - nurp

1
如果您正在使用Next.js并且想要禁用严格模式,请前往您的next.config.js文件并将reactStrictMode设置为false。
module.exports = {
reactStrictMode: false,
};

但是在开发中建议使用严格模式,一旦您确定双重安装是由严格模式引起的,最好启用它。


0

看起来组件会渲染两次,但第一个渲染的组件并没有卸载?至少在使用React 17时我看到了这种行为,当然也可能是我的代码有bug。


我认为这是你的错误。也许你的状态是一个嵌套对象。你应该完全解构它。 - Gorkem Sevim
是的,我也遇到了这个问题,即使在React 18中也是如此。我正在手动删除一个节点。有时我会删除React.StrictMode以确认是否是它引起的问题,还是我的代码中存在一些错误。这是一个有点痛苦和耗时的过程。 - Akash Kumar Seth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接