React16升级避坑指南

September 10, 2017

1. 新增环境依赖

React 16 依赖于ES6新增集合类型 Map 和 Set。若执行环境不支持,可以使用core-js进行polyfill。

import 'core-js/es6/map';
import 'core-js/es6/set';
import React from 'react';
import ReactDOM from 'react-dom';

React16 也依赖于 requestAnimationFrame。

2. 新增客户端增量渲染能力

React16对服务端渲染做了很多优化,真正做到了:

服务端首次渲染,客户端增量渲染(目前还非常不好用)并添加事件`

React15只能做到:服务端首次渲染,客户端添加事件;使用React15时服务端渲染与客户端首次渲染的任何不一致,都会导致服务端渲染输出的DOM树被替换。

React16保证:在development模式使用React15没有任何warning时,可以无缝升级到React16。

但我们很难做到服务端渲染输出的DOM和客户端首次渲染输出的DOM完全一致;这就使得升级React16变得困难。针对这种状况,目前主要有三种升级思路:

2.1 简单升级,完全放弃新特性

基于React15时,我们往往误用renderToString,通过renderToString渲染DOM,然后在客户端通过ReactDOM.render渲染出有局部差异的DOM;然而由于React15对服务端渲染DOM和客户端渲染DOM执行严格的一致性检查,所以会用客户端渲染输出DOM替换服务端渲染输出的DOM;这种情况下使用renderToString并不比renderToStaticMarkup有性能优势。

针对这种情况,升级到React16后,我们可以仍然使用renderToStaticMarkup输出服务端DOM,客户端也会使用ReactDOM.render输出的DOM替换服务端输出的DOM;相比React15没有性能上的降级。

2.3 谨慎升级,客户端不进行增量渲染

放弃服务端渲染会导致用户可交互时间变长,并不是最优选择。在保证服务端渲染输出的DOM和客户端首次渲染输出的DOM完全一致的情况下,我们可以安全地使用React16,在客户端添加DOM事件。

针对客户端首次渲染的差异性要求,可以组件挂载后设置组件的状态来触发组件重新渲染。比如如下代码:

<div className={isInNavigator?"clientClass":"serverClass"}}>
</div>

可改为:

state={
   divClass: "serverClass"
}
componentDidMount(){
    this.setState({
        divClass: "clientClass"
    });
}
<div className={this.state.divClass}>
</div>

2.3 谨慎升级,客户端进行增量渲染

React16新增了客户端首次增量渲染的能力,但我们必须非常小心地使用它,因为它并不如我们想象般聪明。目前发现增量渲染有如下问题:

(1). 无法触发标签属性变更

图片描述

(2). 兄弟DOM结构的删除导致页面混乱

图片描述

图片描述

由于React16的客户端首次增量渲染有不少奇怪的问题,目前较为安全的做法是:

保证服务端渲染输出的DOM结构与客户端首次渲染输出的DOM结构完全一致,客户端不做增量渲染,仅添加DOM事件。

https://github.com/reactjs/react-basic/blob/master/README.md

全面理解React,实现自己的React

通过实现一个简单的React, 来理解React的原理 Continue reading

同构渲染的常见风险

Published on October 01, 2017

一种提取关键样式的方法

Published on July 01, 2017