前言
2022年3月29号,React 18
正式版发布,小明也兴冲冲地开始hooks
学习之旅。某天他使用codesandbox
写了一个小demo
时,他发现组件诡异地渲染了多次,函数组件代码如下:
count.jsx
1 | export default function Count() { |
实现的效果很简单,每隔三秒将count
加1,很简单对不对?
打开这个 demo,同时打开控制台,你就可以看到如下输入:
before render
与effect
一开始都打印了两次,之后before render
每次都诡异地打印了两次
React.StrictMode
这是为什么呢?经过一番查找,发现是React.StrictMode
的锅。React 17
文档中是这样描述 React.StrictMode:
StrictMode
是一个用来突出显示应用程序中潜在问题的工具。与Fragment
一样,StrictMode
不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。
React 17
文档中关于它的作用大概可以归为两类:
- 检测副作用
- 对于在应用中使用已经废弃、过时的方法会发出警告
对于第二点,相信大家都可以理解,毕竟React
现在都发布18
版了,不少以前的方法已经过时或者废弃了,在较新版本的React
中再使用这些方法肯定时不安全的。
那么对于第一点呢?
这不得不提React 18
文档对于StrictMode
的描述:
React offers a “Strict Mode” in which it calls each component’s function twice during development.
大意就是在开发者模式中,StrictMode
会将相应组件执行两次,这下重复执行的疑惑解决了。
但新的疑问产生了,文档中一直提的副作用又是啥?副作用
这个词在React 17
文档中提到的次数很多,如何理解它呢?
在计算机科学中,函数副作用指当调用函数时,除了返回函数值之外,还对主调用函数产生附加的影响 – 维基百科
举个通俗易懂的例子:张三不小心感冒了,鼻塞流涕,医生给他开了感冒药,感冒药的作用就是让我们的身体恢复健康,但是服用的过程中,张三感冒的症状的确是减轻了,但同时他感到浑身乏力、嗜睡,这就副作用
,即意料之外的结果。
事实上,React 18
的文档提到的更多的是purity
,即纯度,这其实是函数式编程的理念,这与React 17文档中提到的无副作用是一个意思,react hooks
函数式组件实际上就是函数式编程理念的体现。编写纯函数带来了一定的心智负担,但随着开发者对其接受度的提高,新文档中大量使用了purity
进行相关描述。文档中提到,纯函数带来了以下优势:
- 多环境运行。例如可以运行在服务端,因为同样的输入,总是对应同样的输出,因此组件可以被其他人复用;
- 减少重复渲染。如果函数组件的输入没有改变,直接复用就好啦,不需要重复渲染。
- 随时中断渲染。在渲染层级较深的组件树时,数据发生了改变,那么
React
可以马上重新开始渲染,而不用等待过时的渲染完成。
因此StrictMode
就是在开发中帮助我们进行检测,保证我们编写的函数组件都是 '纯'
的,这也就解释了为什么开头提到的为什么组件会执行两次,StrictMode
会多执行一次,两次执行的结果相同,证明我们编写的的确是纯函数。
实例
以下列举了一些引发StrictMode
的其他例子
- 在函数内部修改一个已经存在的变量
1 | let guest = 0; |
很明显,当这个组件执行多次,guest的值是逐渐增长的,回想一下纯函数的定义,上述函数组件不是纯函数,因此StrictMode
会进行警告。
- useState
下面的组件定义了counter
变量,我们给useState
传入了初始化函数,组件首次运行时会执行一次这个函数,返回的值作为counter
的初始值,在之后的执行中这个初始化函数会被忽略。
此外,在使用setState
改变counter
的值时,我们为其提供了一个updater
函数,当点击按钮时会更新counter
的值。
因此,理论上首先会打印一次initializer
,然后每按一次按钮,都会打印一次updater
1 | import React, { useState } from "react"; |
而事实上,StrictMode
会帮我们把这两个函数都调用两次,保证其为纯函数。
总结
React.StrictMode
在开发模式下会重复调用组件,保证我们编写的组件
- 检测意外的副作用,确保函数组件时纯函数
- 对于在应用中使用已经废弃、过时的方法会发出警告
- 仅在开发者模式下运行,不影响生产构建
参考
Side Effects: (un)intended consequences