一.特性
fragment
模版支持fragment和string类型,对应ReactElement数组和字符串node
v16.2.0还提供了JSX的fragment支持:<></>
error boundary
组件级错误处理,支持捕获子组件树内部异常,UI层的兜底方案react
portal
容许组件树与DOM树结构不一致,用于hovercards,tooltips等场景git
例如tooltip在DOM结构上target与tip通常是兄弟关系(布局须要),而逻辑上tip是属于target的,是父子关系,portals特性用来处理这种场景web
特殊的,事件冒泡通过处理,portals组件的父组件仍然能接到冒泡通知(React 16以前就内置了用来抹平DOM事件冒泡差别的事件系统,这里顺便支持拐弯冒泡 示例)数组
support for custom DOM attributes
以前内置了HTML/SVG属性名白名单,自定义属性会被拦截并忽略掉,React 16去掉了这个限制性能优化
去掉该限制有2个缘由,其一,这层内置的属性过滤对于非标准的(好比proposal阶段的)新属性和其它库/框架(好比Angular、Polymer)很不友好;其二,bundle里要内置一份体积不小的属性白名单,维护起来还挺麻烦架构
improved server-side rendering
号称比React 15快3倍(benchmark场景,某业务场景听说1.3倍),作了几件事:app
支持stream框架
构建时去掉了多余的process.env(在node环境访问这个变量很耗时)访问frontend
client再也不计算checksum,而是尽可能复用现有DOM(与贯彻落实DOM node复用的inferno神似,但inferno复用好像遇到一些问题,如今只做为可选项而不是亮点特性提供)
注意:React 16貌似也存在一些DOM node复用的问题:
However, it’s dangerous to have missing nodes on the server render as this might cause sibling nodes to be created with incorrect attributes.
P.S.具体要注意哪些危险场景,官方后面可能会给出专门的博客,暂时没有说清楚
reduced file size
React bundle瘦身(重构,扁平化打包策略,并换用rollup),体积小了30%
二.***
变化最大的应该是***,此次认真实现了一下(以前的***像是地上捡的)
1.新API
server侧新增了renderToNodeStream, renderToStaticNodeStream分别对应renderToString, renderToStaticMarkup
client侧新增了hydrate
2.宽松的一致性校验
client侧校验没那么严格了:
React 15中,client会对拿到的***结果作字符级的一致性校验,一点不匹配就由client从新生成并整个替掉
React 16容许属性顺序不一致,并且不给自动修复不一致的属性,并且遇到不匹配的标签结构,会作子树级修改,而不是整个替掉
另外,还去掉了Server HTML结构上的checksum(data-react-checksum)以及id(data-reactid),响应体大小会下降很多:
<!-- react 15 --> <div data-reactroot="" data-reactid="1" data-react-checksum="122239856"> <!-- react-text: 2 -->This is some <!-- /react-text --> <span data-reactid="3">server-generated</span> <!-- react-text: 4--> <!-- /react-text --> <span data-reactid="5">HTML.</span> </div> <!-- react 16 --> <div data-reactroot=""> This is some <span>server-generated</span> <span>HTML.</span> </div>
3.性能优化
默认去掉了多余的process.env.NODE_ENV访问,不须要手动编译去掉
***再也不建立一次性的virtual DOM,整个快了很多
支持stream,带来的性能优点以下:
server边造边发,而不用等待***完毕才一次完整发过来,TTFB(the time to first byte)更快
client边接边画,而不用等到响应内容完整了才开始绘制,解析、绘制、外部资源加载等时间点都提早了
4.不支持Error Boundary和Portal
React 16 ***不支持Error Boundary和Portal
服务端子组件渲染出错,不会被Error Boundary拦住。为了stream性能优点,牺牲了Error Boundary:
This is intentional / a known limitation. With streaming rendering it’s impossible to “call back” markup that has already been sent, and we opted to keep renderToString and renderToNodeStream’s output identical.
不只renderToNodeStream, renderToStaticNodeStream不支持Error Boundary,renderToString也不支持,如上面说的,为了保持输出结果一致,没有维护2套机制
P.S.关于*** Error Boundary的更多信息,请查看componentDidCatch doesn’t work in React 16’s renderToString
而Portal特性可能形成“回流”,与Error Boundary是一个道理,在stream机制下没法支持(想要往已经发送出去的stream里插入Portal内容,固然不可能)
三.Fiber
全新的核心架构,(花了2年)整个重写了组件渲染机制,最关键的特性是异步渲染(async rendering),实现了可调度渲染(完全解决mount流程一旦开始就没法中断的问题)
重构过程
这样庞大的一个东西,伤筋动骨的重构执行过程颇有意思。简单地说:
不拉新分支去搞。而是经过useFiber特性开关切换,说是为了简化平常维护/冲突处理等
第一步作个骨架(skeleton)出来。支持部分API,再慢慢跑通全部测试用例(所谓TDD,测试驱动开发,最后搞出来2000个case)
工程化辅助手段。包括进度追踪、单测结果追踪(便于发现一次提交修复了什么,干坏了什么,手段很是简单:把tests-failing.txt, tests-passing.txt添加到git追踪)、持续的生产环境验证(所谓dogfooding,从早期到最后单测经过的整个过程都在不断地进行“实战”验证,算是一种看得见的信念)
找块合适的业务做为试验田(testbed)。差很少稳定后,经过实际业务来证实ready for production,经过A/B测试出数据,让2亿用户帮忙感觉一下,后来再切到全量;同时对内系统全切,扩大验证场景;最后再对React Native应用来个灰度
不直接上新机制。暂时仍然以同步方式执行(虽然Fiber支持异步),准备再憋几个月,好平滑过渡
P.S.具体重构过程见React 16: A look inside an API-compatible rewrite of our frontend UI library
因此暂时不支持异步渲染:
This initial React 16.0 release is mostly focused on compatibility with existing apps. It does not enable asynchronous rendering yet. We will introduce an opt-in to the async mode later during React 16.x. We don’t expect React 16.0 to make your apps significantly faster or slower, but we’d love to know if you see improvements or regressions.
优点
新特性
组件级错误处理、render返回多组件等以前不太容易实现的特性,重构以后均可以造出来了
体验上的优点
Fiber并不必定更快,但会更流畅(拆分渲染任务并均衡调度,避免长时间占用主线程),另外还有任务优先级控制,让动画等优先执行
差别至关明显,见React Stack vs Fiber
参考资料
React v16.0
What’s New With Server-Side Rendering in React 16
How React Fiber can make your web and mobile apps smoother and more responsive