react 严格模式默认渲染两次,除了关闭严格模式还能如何解决

1,043 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

背景

最近做项目遇到了这样的场景,在进入页面的时候使用react.useEffect,在其中进行网络的请求,但是我发现刚进入页面的时候会请求两次,正常情况下是显示正常的,毕竟多查了一次也没有什么问题,但是如果请求出错了,那么出错的处理就会重复一遍,也就是说,如果接口出错,那么错误的弹窗会多弹出一次,总计弹出两次。

原因

检测意外的副作用

从概念上讲,React 确实分两个阶段工作:

  • 渲染阶段确定需要对 DOM 等进行哪些更改。在这个阶段,React 调用render然后将结果与之前的渲染进行比较。
  • 提交阶段是 React 应用任何更改的时候。(在 React DOM 的情况下,这是 React 插入、更新和删除 DOM 节点的时候。)React在这个阶段也像componentDidMount和一样调用生命周期。componentDidUpdate

提交阶段通常非常快,但渲染可能很慢。出于这个原因,即将到来的并发模式(默认情况下尚未启用)将渲染工作分成几部分,暂停和恢复工作以避免阻塞浏览器。这意味着 React 可能在提交之前多次调用渲染阶段生命周期,或者它可能在根本不提交的情况下调用它们(因为错误或更高优先级的中断)。

渲染阶段生命周期包括以下类组件方法:

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

因为上述方法可能会被多次调用,所以它们不包含副作用很重要。忽略此规则会导致各种问题,包括内存泄漏和无效的应用程序状态。不幸的是,很难检测到这些问题,因为它们通常是不确定的

严格模式不能自动为您检测副作用,但它可以通过使它们更具确定性来帮助您发现它们。这是通过有意双重调用以下函数来完成的:

  • 类组件constructor,rendershouldComponentUpdate方法
  • 类组件静态getDerivedStateFromProps方法
  • 功能组件体
  • 状态更新函数( 的第一个参数setState
  • 传递给useStateuseMemo或的函数useReducer

笔记:

这仅适用于开发模式。在生产模式下不会重复调用生命周期。

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

从 React 18 开始,React 不再抑制任何日志。但是,如果您安装了 React DevTools,则第二次调用的日志会显得有些暗淡。React DevTools 还提供了一个设置(默认关闭)来完全抑制它们。

解决

现在知道了 react 渲染页面两次的原因,但是如何解决呢?

我在网上搜了一下,几乎所有方法都是说可以关掉react的严格模式,但是我又想用严格模式,于是我用了另一种办法:配置当前环境为生产环境。

从上面的原因部分,我们知道,react只有在开发环境才会渲染两次,那么就把当前环境设置为生产环境来解决这个问题。

我用的是vite,所以我在.env文件加了NODE_ENV=production,设置之后文件就只渲染一次啦!

refer:reactjs.org/docs/strict…