React 17 要来了,您准备好了么?

写在前面

React 最近发布了v17.0.0-rc.0,距上一个大版本v16.0(发布于 2017/9/27)已经过去近 3 年了

与新特性云集的 React 16及先前的大版本相比,React 17 显得格外特殊——没有新特性:

React v17.0 Release Candidate: No New Features

不仅如此,还带上来了 7 个 breaking change……

一.真没有新特性?

React 官方对 v17 的定位是一版技术改造,主要目标是降低后续版本的升级成本:

This release is primarily focused on making it easier to upgrade React itself.

因此 v17 只是一个铺垫,并不想发布重大的新特性,而是为了 v18、v19……等后续版本能够更平滑、更快速地升上来:

When React 18 and the next future versions come out, you will now have more options.

但其中有些改造不得不打破向后兼容,于是提出了 v17 这个大版本变更,顺便搭车卸掉两年多积攒的一些历史包袱

二.渐进式升级成为了可能

在 v17 之前,不同版本的 React 无法混用(事件系统会出问题),所以,开发者要么沿用旧版本,要么花大力气整个升级到新版本,甚至一些常年没有需求的长尾模块也要整体适配、回归测试。考虑到开发者的升级适配成本,React 维护团队同样束手束脚,废弃 API 不敢轻易下掉,要么长时间、甚至无休止地维护下去,要么选择放弃那些老旧的应用

而 React 17 提供了一个新的选项——渐进式升级,允许 React 多版本并存,对大型前端应用十分友好,比如弹窗组件、部分路由下的长尾页面可以先不升级,一块一块地平滑过渡到新版本(参考官方 Demo)

P.S.注意,(按需)加载多个版本的 React 存在着不小的性能开销,同样应该慎重考虑

多版本并存与微前端架构

多版本并存、新旧混用的支持让微前端架构所期望的渐进式重构成为了可能:

渐进地升级、更新甚至重写部分前端功能成为了可能

与 React 支持多版本并存、渐进地完成版本升级相比,微前端更在意的是允许不同技术栈并存,平滑地过渡到升级后的架构,解决的是一个更宽的问题

另一方面,当 React 技术栈下多版本混用难题不复存在时,也有必要对微前端进行反思:

一些问题是不是由技术栈自身来解决更为合适?

多技术栈并存是常态还是短期过渡?

对于短期过渡,是否存在更轻量的解决方案?

关于微前端在解决什么问题的更多思考,见Why micro-frontends?

三.7 个 Breaking change

事件委托不再挂到 document 上

之前多版本并存的主要问题在于React 事件系统默认的委托机制,出于性能考虑,React 只会给document挂上事件监听,DOM 事件触发后冒泡到document,React 找到对应的组件,造一个 React 事件(SyntheticEvent)出来,并按组件树模拟一遍事件冒泡(此时原生 DOM 事件早已冒出document了):

[caption id=“attachment_2263” align=“alignnone” width=“625”]react 16 delegation react 16 delegation[/caption]

因此,不同版本的 React 组件嵌套使用时,e.stopPropagation()无法正常工作(两个不同版本的事件系统是独立的,都到document已经太晚了):

If a nested tree has stopped propagation of an event, the outer tree would still receive it.

P.S.实际上,Atom 在早些年就遇到了这个问题

为了解决这个问题,React 17 不再往document上挂事件委托,而是挂到 DOM 容器上:

[caption id=“attachment_2264” align=“alignnone” width=“625”]react 17 delegation react 17 delegation[/caption]

例如:

const rootNode = document.getElementById(‘root’);
// 以为 render 为例
ReactDOM.render(, rootNode);
// Portals 也一样
// ReactDOM.createPortal(, rootNode)
// React 16 事件委托(挂到 document 上)
document.addEventListener()
// React 17 事件委托(挂到 DOM container 上)
rootNode.addEventListener()

另一方面,将事件系统从document缩回来,也让 React 更容易与其它技术栈共存(至少在事件机制上少了一些差异)

向浏览器原生事件靠拢

此外,React 事件系统还做了一些小的改动,使之更加贴近浏览器原生事件:

onScroll不再冒泡

onFocus/onBlur直接采用原生focusin/focusout事件

捕获阶段的事件监听直接采用原生 DOM 事件监听机制

注意,onFocus/onBlur的下层实现方案切换并不影响冒泡,也就是说,React 里的onFocus仍然会冒泡(并且不打算改,认为这个特性很有用)

DOM 事件复用池被废弃

之前出于性能考虑,为了复用 SyntheticEvent,维护了一个事件池,导致 React 事件只在传播过程中可用,之后会立即被回收释放,例如:

你可能感兴趣的:(React 17 要来了,您准备好了么?)