携手创作,共同成长!这是我参与「掘金日新计划 · 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
,render
和shouldComponentUpdate
方法 - 类组件静态
getDerivedStateFromProps
方法 - 功能组件体
- 状态更新函数( 的第一个参数
setState
) - 传递给
useState
、useMemo
或的函数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…