大家好,我卡颂。
5 月 30 日刚好是React
10 周年纪念日。
我棘手拉了下 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
的开发模式相干。比方:
与状态的流转相干的:
useState
useReducer
useContext
与解决副作用相干的:
useEffect
useLayoutEffect
与进步操作自由度相干的:
useRef
与性能优化相干的:
useMemo
useCallback
与调试相干:
useDebugValue
随着 React
继续迭代,又引入了几个 hook
,实质来说他们都是为了欠缺CSR
的开发模式,对现有 hook
能力进行补充或束缚:
useImperativeHandle
(管制useRef
避免其失控)useEffectEvent
(对useEffect
能力的补充)useInsertionEffect
(对useEffect
场景的补充)- useMemoCache(缩小性能优化心智累赘)
这里简略聊聊 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
:
useTransition
useDeferredValue
这 2 个 hook
的实质都是升高更新的优先级,更新 意味着 视图渲染 ,所以当更新领有不同优先级后,这意味着 视图渲染 领有不同优先级。
这就是并发更新的实践根底。
然而,并发更新的呈现,突破了 React
因循多年的 一次更新对应一次渲染 的模式。
为了让现有的库兼容并发模式,推出了如下hook
:
useMutableSource
useSyncExternalStore
所以,上述 2 个 hook
次要是面向开源库作者。
RSC
期间
RSC
(服务端组件)是一个盛大的工程,他的实现不是欲速不达的,这一点从新出的 hook
就能看出。
既然是服务端组件,那就波及到组件在服务端渲染。那么,对于存在惟一标识(比方上面的id props
)的组件,如何保障这个惟一标识在服务端与客户端统一呢?
<SomeCpn id={id}/>
如果组件仅在一端渲染,简略应用 Math.random()
就能取得惟一标识:
const id = Math.random();
<SomeCpn id={id}/>
但如果这段逻辑在服务端 / 客户端都运行一次,显然 id
就不惟一了。
为了生成在服务端 / 客户端惟一的id
,有了:
useId
在并发期间,因为引入了 渲染优先级 的概念,那势必存在一些因为优先级有余,而处于 pending
中的渲染。
如何展现 渲染的 pending 状态 呢?React
引入了 <Suspense>
组件。
到了 RSC
期间,React
团队发现,渲染的 pending 状态 是pending
,数据申请的 pending 状态 不也是 pending
吗?
换言之,任何须要两头 pending
状态的流程,不都能够纳入 <Suspense>
的治理范畴?
那该怎么标记一个流程能够被纳入 <Suspense>
的治理呢?于是有了:
use
通过这个 hook
申明的流程中的 pending
状态都会被纳入 <Suspense>
的治理。
既然 <Suspense>
越来越重要,那咱们是不是要针对他做些优化?既然 <Suspense>
能够在不同视图之间切换,那为他减少缓存显然是种不错的优化形式,于是有了:
- useCacheRefresh(用于建设
<Suspense>
缓存)
到这一步,RSC
的基础设施算是搭好了,下一步该构建下层利用了。
在浏览器端,与 RSC
理念最符合的便是 form
标签,围绕 form
标签的 action
属性,React
推出了如下hook
:
useOptimistic
useFormStatus
这 2 个 hook
都是为了优化 表单提交 这一场景(也能够说是 RSC
与客户端的交互场景)。
对于这 2 个
hook
,更具体的解释能够参考 form 元素是 React 的将来一文
总结
如果说 CSR
期间的 hook
都是面向开发者间接应用的。那么并发期间最后的 2 个 hook
(useTransition
、useDeferredValue
)曾经鲜有开发者应用了,而前期相似useMutableSource
这样的hook
,一般开发者则基本用不到。
同样的,再往后的 RSC
期间的所有hook
,一般开发者都用不到。他们都是为其余库、框架(比方Next.js
)提供的。
这标记着 React
倒退方向的一直变动:
- 晚期,定位是前端框架,次要为了解决
facebook
本身问题,顺便开源,受众是开发者 - 中期,定位是底层
UI
库,受众是开源库作者 - 以后,定位是
web
底层操作系统,受众是下层全栈框架