[译]我的 React 组件会渲染两次,我快疯了

您所在的位置:网站首页 react运行命令 [译]我的 React 组件会渲染两次,我快疯了

[译]我的 React 组件会渲染两次,我快疯了

2023-03-23 05:16| 来源: 网络整理| 查看: 265

原文地址:My React components render twice and drive me crazy 原文作者:Marios Fakiolas 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:tanglie1993 校对者:racheldev, lhd951220 我的 React 组件会渲染两次,我快疯了

很多使用现代 React 的前端开发者,时常遇到组件渲染两次的情况。这害得他们都快把自己薅秃了。

另外一些人注意到了这个行为,但是他们觉得这是 React 运行的原理。又有些人会在 React 官方 repository 上发起工单,把这当做一个 bug 上报。

所以开发者社区中肯定对此存在着一些困惑。😬

这些事情发生的原因是 React.StrictMode。

我们来看一些真实的例子,复现一下这种情况,然后研究它为什么会发生吧。

函数组件的例子

我们可以从运行一个新的 CRA 安装命令开始:

npx create-react-app my-app && cd my-app 复制代码

我们稍稍改动 App.js ,增加一个超级简单的 console.log 语句:

function App() { console.log('I render 😁'); return ( ); } 复制代码

现在我们可以通过 yarn start 启动我们的应用,并且在浏览器中打开 http://localhost:3000:

我的 React 组件会渲染两次,我快疯了

嗯,I render 😁 语句只输出了一次,所以我们不能通过一个超级简单的函数组件实现渲染两次。

带状态的函数组件例子

如果我们使用一个 React hook,然后在函数组件中加入一些状态语句会发生什么?

function App() { const [clicks, setClicks] = React.useState(0); console.log('I render 😁'); return ( setClicks(clicks => clicks + 1)}> Clicks: {clicks} ); } 复制代码

我们再看一下浏览器:

我的 React 组件会渲染两次,我快疯了

实现了!它首先渲染了两次,然后每当我们点击加入的按钮时,都渲染两次。

显然,React.useState 影响了组件在重复渲染方面的行为。

生产环境中带状态的函数组件例子

生产环境 bundle 又如何呢?为了检查这一点,我们需要首先构建自己的应用,然后在 3000 端口中通过 serve 之类的包使用它:

yarn build && npx serve build -l 3000 复制代码

在浏览器中再次打开 http://localhost:3000:

我的 React 组件会渲染两次,我快疯了

哎呦!调试语句在开始时打印了一次,并且在我们每次点击按钮时打印一次。

如我们所见,渲染两次的行为在生产环境中肯定不能复现,尽管我们对于 React.useState 的用法是完全一致的。

为什么会发生这种事?

如上所述,原因是 React.StrictMode。如果我们在应用中检查我们之前使用 CRA 运行的文件,我们会发现,我们的 组件被它包裹:

ReactDOM.render( , document.getElementById('root') ); 复制代码

显然,重新渲染并不是一个 bug,或者和库的渲染机制有关的东西。正相反,它是 React 提供的一种调试机制 🤗。

# 什么是 React.StrictMode?

React.StrictMode 是在 2018 年的 16.3.0 版本中引入的组件。一开始,它只用在类组件中,而在 16.8.0 中,它对 hook 同样适用。

就像在版本说明中提及的一样:

React.StrictMode 是帮助应用适应异步渲染的组件

所以它应该用来帮助工程师避免常见的错误,并使他们的 React 应用抛弃过时的 API,从而逐步升级。

这些提示对于更好地调试是有帮助的,因为这个库正在向异步渲染时代迈进,所以大的改动时时发生。

很有用,对吧?

为什么会渲染两次呢?

我们从使用 React.StrictMode 中获得的好处之一是,它帮助我们检测到渲染期生命周期的预期之外的副作用。

这些生命周期有:

constructor componentWillMount (或者 UNSAFE_componentWillMount) componentWillReceiveProps (或者 UNSAFE_componentWillReceiveProps) componentWillUpdate (或者 UNSAFE_componentWillUpdate) getDerivedStateFromProps shouldComponentUpdate render setState 更新函数 (第一个参数)

所有这些方法都被调用不止一次,所以避免副作用是十分重要的。如果我们无视这个原则,就有可能造成状态不一致问题或者内存泄漏。

React.StrictMode 不能马上检测到副作用,但是它可以通过故意调用一些关键函数两次,来帮助我们发现副作用。

这些函数有:

类组件 constructor、render 以及 shouldComponentUpdate 方法 类组件静态 getDerivedStateFromProps 方法 方法组件的方法体 状态更新函数 (setState 的第一个参数) 传给 useState、useMemo、或 useReducer 的函数

这个行为肯定对性能有一些影响,但我们不应该担心,因为它只在开发而不是生产环境中发生。

这就是我们只有在开发环境下使用带 React.useState 的组件函数,才可以成功复现渲染两次的原因。Cheers!!

如果你需要继续深入研究 React.StrictMode,你可以阅读 官方文档。

如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。

掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。

阿里巴巴本地生活招聘

团队需要多名前端开发工程师,校招/社招均可,base杭州或上海。 感兴趣的可以发送简历到 [email protected] 期待你的加入。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3