​不数不知道,React已经有22个Hook了

开发 前端
如果说CSR时期的hook都是面向开发者直接使用的。那么并发时期最初的2个Hook(useTransition、useDeferredValue)已经鲜有开发者使用了,而后期类似useMutableSource这样的Hook,普通开发者则根本用不到。

大家好,我卡颂。

5月30日刚好是React10周年纪念日。

图片

我顺手拉了下React最新代码,这一看不要紧,居然已经有22个hook了。

其中:

  • react包导出了21个。
  • react-dom包导出了1个(useFormStatus)。

图片

本文会从React这些年发展脉络的角度,聊聊这些hook的作用。

时代的更迭

截止当前,React的发展主要经历了3个时期:

  • CSR时期(客户端渲染时期)
  • 并发时期
  • RSC时期(服务端组件时期)

当前的22个hook也都是这3个时期的产物。

CSR时期

时间回到2013年,为了解决facebook日益复杂的交互,「jordwalke」开发了React。经过一段时间摸索,React逐渐形成一套满足CSR的开发模式。

这套开发模式从ClassComponent迁移到FunctionComponent后,便形成了最初的一批hook。这些hook都与CSR的开发模式相关。比如:

与状态的流转相关的:

  1. useState
  2. useReducer
  3. useContext

与处理副作用相关的:

  1. useEffect
  2. useLayoutEffect

与提高操作自由度相关的:

  1. useRef

与性能优化相关的:

  1. useMemo
  2. useCallback

与调试相关:

  1. useDebugValue

随着React持续迭代,又引入了几个hook,本质来说他们都是为了完善CSR的开发模式,对现有hook能力进行补充或约束:

  1. useImperativeHandle(控制useRef防止其失控)
  2. useEffectEvent(对useEffect能力的补充)
  3. useInsertionEffect(对useEffect场景的补充)
  4. useMemoCache[1](减少性能优化心智负担)

这里简单聊聊useMemoCache。长久以来,不管是ClassComponent的shouldComponentUpdate,还是FC中2个性能优化相关hook,都存在比较重的心智负担,比如:

  • 开发者需要考虑是否需要性能优化
  • 开发者需要考虑何时使用useMemo、useCallback

为了解决这个问题,在2021年的React Conf,黄玄带来了「能够通过编译器生成等效于useMemo、useCallback代码」的方案 —— React Forget。

图片

useMemoCache就是React内部为React Forget提供缓存支持的hook。

所以这个hook是给编译器用的,而不是我们普通开发者。

并发时期

在13年诞生之初,React的作者「jordwalke」就指出 —— React未来会发展「并发特性」。

这并不是什么高瞻远瞩的预言,React本身是个重运行时的框架,这意味着他的迭代方向需要围绕「运行时」展开。而「并发特性」是一种优秀的运行时性能优化策略。

随着并发特性落地,首先推出的是2个并发相关hook:

  1. useTransition
  2. useDeferredValue

这2个hook的本质都是降低更新的优先级,「更新」意味着「视图渲染」,所以当更新拥有不同优先级后,这意味着「视图渲染」拥有不同优先级。

这就是并发更新的理论基础。

但是,并发更新的出现,打破了React沿袭多年的「一次更新对应一次渲染」的模式。

为了让现有的库兼容并发模式,推出了如下hook:

  1. useMutableSource
  2. useSyncExternalStore

所以,上述2个hook主要是面向开源库作者。

RSC时期

RSC(服务端组件)是一个浩大的工程,他的实现不是一蹴而就的,这一点从新出的hook就能看出。

既然是服务端组件,那就涉及到组件在服务端渲染。那么,对于存在唯一标识(比如下面的id props)的组件,如何保证这个唯一标识在服务端与客户端一致呢?

<SomeCpn id={id}/>

如果组件仅在一端渲染,简单使用Math.random()就能获得唯一标识:

const id = Math.random();

<SomeCpn id={id}/>

但如果这段逻辑在服务端/客户端都运行一次,显然id就不唯一了。

为了生成在服务端/客户端唯一的id,有了:

  1. useId

在并发时期,由于引入了「渲染优先级」的概念,那势必存在一些由于优先级不足,而处于pending中的渲染。

如何展示「渲染的pending状态」呢?React引入了<Suspense>组件。

到了RSC时期,React团队发现,「渲染的pending状态」是pending,「数据请求的pending状态」不也是pending吗?

换言之,任何需要中间pending状态的流程,不都可以纳入<Suspense>的管理范围?

那该怎么标记一个流程可以被纳入<Suspense>的管理呢?于是有了:

  1. use

通过这个hook声明的流程中的pending状态都会被纳入<Suspense>的管理。

既然<Suspense>越来越重要,那我们是不是要针对他做些优化?既然<Suspense>可以在不同视图之间切换,那为他增加缓存显然是种不错的优化方式,于是有了:

  1. useCacheRefresh[2](用于建立<Suspense>缓存)

到这一步,RSC的基础设施算是搭好了,下一步该构建上层应用了。

在浏览器端,与RSC理念最契合的便是form标签,围绕form标签的action属性,React推出了如下hook:

  1. useOptimistic
  2. useFormStatus

这2个hook都是为了优化「表单提交」这一场景(也可以说是RSC与客户端的交互场景)。

关于这2个hook,更详细的解释可以参考form 元素是 React 的未来一文。

总结

如果说CSR时期的hook都是面向开发者直接使用的。那么并发时期最初的2个hook(useTransition、useDeferredValue)已经鲜有开发者使用了,而后期类似useMutableSource这样的hook,普通开发者则根本用不到。

同样的,再往后的RSC时期的所有hook,普通开发者都用不到。他们都是为其他库、框架(比如Next.js)提供的。

这标志着React发展方向的不断变化:

  • 早期,定位是前端框架,主要为了解决facebook自身问题,顺便开源,受众是开发者。
  • 中期,定位是底层UI库,受众是开源库作者。
  • 当前,定位是web底层操作系统,受众是上层全栈框架。

参考资料

[1]useMemoCache:https://github.com/facebook/react/pull/25123。

[2]useCacheRefresh:https://github.com/reactwg/react-18/discussions/25。

责任编辑:姜华 来源: 魔术师卡颂
相关推荐

2023-01-02 10:08:42

StampedLocAQS框架

2015-09-18 16:11:04

图标桌面环境KDE

2024-01-26 06:26:42

Linuxfzf工具

2015-07-14 10:18:42

Windows 10正式版

2018-04-26 13:33:20

Python语法Bug

2020-09-27 06:47:20

5G网络运营商

2022-02-25 11:04:21

Reactlanelanes

2022-10-12 08:22:44

Guava工具Collection

2019-10-28 08:44:29

Code Review代码团队

2023-12-21 14:40:09

Python编程语言

2024-05-20 09:27:00

Web 开发CSS

2019-11-29 16:49:42

HTML语言开发

2020-06-12 09:20:33

前端Blob字符串

2020-07-28 08:26:34

WebSocket浏览器

2022-04-12 09:04:57

前端监控数据采集

2019-12-24 09:49:02

微软英语浏览器

2017-01-17 15:46:17

路由器地址网关

2022-06-18 23:03:05

Seata分布式事务

2023-06-30 08:01:04

Reactuse关键词

2023-06-02 07:04:24

宏碁映泰技嘉
点赞
收藏

51CTO技术栈公众号