[译]React v16.0 正式发布

@GuoYongfeng 2017-09-27 06:20:20发表于 iuap-design/blog

[译]React v16.0 正式发布

非常高兴和大家宣布 ---- React v16.0 正式版发布了,这些变化包含很多大家一直以来期待的特性,包括 fragments, error boundaries, portals,、对自定义 DOM 属性的支持、改进的服务器端渲染,以及文件大小的减少

New render return types: fragments and strings (render 函数可以返回 HTML 片段和字符串)

你可以在 render 函数中返回一个元素数组,类似平时写的其他数组一样,不过需要注意的是,得给数组中的每个元素加上 key 属性标识唯一性,不然会出现 warning(后续,也有可能在 JSX 中加上一个特殊的语法,到时就不用写这个 key 属性了,这是后话)。

render() {
  // No need to wrap list items in an extra element!
  return [
    // Don't forget the keys :)
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];
}

当然,我们也可以直接返回一个字符串。

render() {
  return 'Look ma, no spans!';
}

其实,不仅仅是新增的返回的这两种,render 函数还能返回以下这些类型(详细请查看这里):

  • React elements. Typically created via JSX. A element can either be a representation of a native DOM component (
    ), or a user-defined composite component ().
  • String and numbers. These are rendered as text nodes in the DOM.
    Portals. Created with ReactDOM.createPortal.
  • null, 这种情况就是啥也不渲染.
  • Booleans. Render nothing. (Mostly exists to support return && pattern, where test is boolean.)

Better error handling(错误处理和错误信息提示更友好)

以前,渲染过程中的运行时错误可能会使React处于断开状态,产生隐秘的错误消息,并需要页面刷新才能恢复。 为了解决这个问题,React 16使用了更有弹性的错误处理策略。 默认情况下,如果组件的渲染或生命周期方法中抛出了错误,则会从根目录卸载整个组件树。 这样可以防止显示损坏的数据。 但是,这可能不是理想的用户体验。

每次发生错误时,不要卸载整个应用程序,您可以使用错误边界。 错误边界是捕获子树内部错误的特殊组件,并显示一个备用UI。 想到错误边界,如try-catch语句,但是对于React组件。

有关更多详细信息,请查看我们以前在React 16中的错误处理文章。

Portals

Portals 提供了一种非常好的方式将 children 呈现到存在于父组件的DOM层次结构之外的DOM节点。

render() {
  // React does *not* create a new div. It renders the children into `domNode`.
  // `domNode` is any valid DOM node, regardless of its location in the DOM.
  return ReactDOM.createPortal(
    this.props.children,
    domNode,
  );
}

对于 createPortal 的使用可以这样来调用。

ReactDOM.createPortal(child, container)

点击portals 的文档 查看完整示例。

Better server-side rendering(更好的支持服务端渲染)

React v16 中,服务端渲染完全被重写,渲染的性能非常快,而且它支持流式传输(streaming),因此您可以更快地向 client 端发送字节。而且,由于采用了一个新的封装策略来编译 process.env 检查(不管你信不信,在 Node 中读取 process.env 真的很慢!),您不再需要绑定 React 来获得良好的服务器呈现性能。

Sasha Aickin (React 项目核心成员)写了一篇非常棒的文章来说明 React v16中的在 SSR 方面的改进。根据 Sasha 的综合基准测试(synthetic benchmarks),React 16 中的服务器呈现速度大大高于 React 15三倍

当与 React 15process.env 进行比较时,在 Node v4 中的性能提高了2.4倍,在 Node v6 中的性能提升了3倍,并且在新的 Node v8.4版本中改善了3.8倍,而如果您在React 15中进行比较而不进行编译,则在最新版本的Node!中,React 16在SSR中有一个完整的数量级增益。
**请注意:**这些数字是基于综合基准,可能在实际的应用中的表现和这些数字会有出入。

此外,React 16 可以更好地将服务器输出的 HTML 发送到客户端。它不再需要初始渲染与服务器的结果完全匹配。相反,它将尝试尽可能重用现有的DOM。没有更多的校验和!一般来说,我们不建议您在客户端和服务器上呈现不同的内容,但在某些情况下(例如时间戳)可能会有用。

有关详细信息,请参阅ReactDOMServer的文档

Support for custom DOM attributes(支持自定义 DOM 属性)

React 可以将无法识别的 HTMLSVG 属性传递给 DOM,而不是忽略它们,并且这有额外的好处:允许我们摆脱 React 的大多数属性白名单,从而减少文件大小。

Reduced file size(减小文件体积)

React v16 比之前小了很多。

  • react is 5.3 kb (2.2 kb gzipped), 之前是 20.7 kb (6.9 kb gzipped).
  • react-dom is 103.7 kb (32.6 kb gzipped), 之前是 141 kb (42.9 kb gzipped).
  • react + react-dom is 109 kb (34.8 kb gzipped), 之前是 161.7 kb (49.8 kb gzipped).

相比之下,与之前的版本相比,这相当于减少了 32% 的文件体积(30%的gzip)。

尺寸差异部分归因于包装的变化。React 现在使用 Rollup 为每种不同的目标格式创建平面捆绑,从而导致大小和运行时性能的胜利。

扁平捆绑格式还意味着,无论您使用Webpack 还是 Browserify,预制 UMD捆绑包还是任何其他系统,React对捆绑包大小的影响大致一致。

MIT licensed(将原来的BSD+专利的协议修改为MIT)

relicensing-react-jest-flow-and-immutable-js 这篇文章说明了协议修改的来龙去脉。React 16 的协议已经修改为 MIT 协议了 ,对于那些无法立即升级的同学,我们发布了 V15.6.2,这个版本也是 MIT 协议的。

New core architecture( Fiber )

React v16 是基于 Fiber 核心架构的第一个版本,你可以在 facebook 工程博客 中看到有关这个项目的详细信息。

Fiber 负责 React 16 中的大部分新功能,如 error boundaries and fragments。 在接下来的几个版本中,您可以期待更多新功能,因为我们开始解锁 React 的全部潜力。

async rendering(异步渲染)是我们正在研究的最令人激动的领域 ---- 我们的策略是通过定期向浏览器执行协同调度渲染工作。 使用异步渲染后,我们发现,整个应用程序表现的更加灵敏,因为 React 解决了主线程阻塞的问题。

安装和使用新版本

npm 下载:

npm install --save react@^16.0.0 react-dom@^16.0.0

CDN 方式:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Upgrading(一些相关改进)

虽然React 16包含了重大的内部变化,但在升级方面,您可以像任何其他主要的React版本一样想到这一点。 自从今年早些时候起,我们一直为 FacebookMessenger.com 用户提供 React 16,并且发布了几个测试版和发布候选版本来排除其他问题。

除了少数例外,如果您的应用程序在 v15.6 运行时没有任何警告,那么它在 v16.0 运行也能正常运行。

New deprecations 废弃的 API

  • 如果是服务端渲染,用 ReactDOM.hydrate 替代 ReactDOM.render
  • 如果只是客户端渲染,用 ReactDOM.render

React Addons 一些套件

具体查看之前的声明discontinuing-support-for-react-addons

Breaking changes 跳跃式升级

React 16 包含了一小部分的 breaking changes,而且影响面比较小。

  • unstable_handleError 这个 API 已经被重命名为 componentDidCatch
  • 关于 setState 这个 API 的一些变化:
    • 直接调用 setState 这个 API 将不会直接导致重新渲染,你可以在生命周期中和更新相关的钩子函数中控制是否要 re-render
    • 不要在 render 函数中直接调用 setState 方法,因为这样总是会导致更新渲染。
    • setState( newState, callback ) 的第二个参数是一个 callback 回调函数,回调函数之前是在所有组件渲染后才会被执行,现在是在 componentDidMount / componentDidUpdate 之后就会立即执行。

JavaScript Environment Requirements 对 JS 环境的要求

React 16 中用到了 Map 和 Set ,所以需要使用 core-js 或者 babel-polyfill 来处理兼容问题:

import 'core-js/es6/map';
import 'core-js/es6/set';

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

React 16 无论是在测试环境还是生产环境,都依赖了 requestAnimationFrame 所以它的兼容问题也得处理:

global.requestAnimationFrame = function(callback) {
  setTimeout(callback, 0);
};