【译】2016React大会之React展望

华丽的子标题

Posted by zhongjie-chen on April 16, 2016

译者按:2016年React.js大会在今年1月份举行,2月底放出了视频,本文翻译的是其中一个演讲What Lies Ahead(自备梯子),介绍了React目前的进展,以及未来的研发方向。

Hi, 我是Ben,在React团队工作,今天我要介绍的是我们对React未来的构想。

当我们在考虑“React还有哪些改进空间?”“还有什么问题可以用React解决?”的时候,我们都在尝试回答一个问题——React如何帮助(开发者)开发极致的应用?这个问题有两个部分要考量。首先,一个极致的应用明显应该有良好的用户体验。同时,我们认为开发体验的地位也是举足轻重。所以今天我们要讨论这两个话题。

在我继续阐述之前,我需要声明一下,我今天要讲的东西基本上都是一个idea,我们还没有为之写过代码,我们也可能不会实现。然而这些都是我们特别想改进的地方,而我们团队太小,实现起来要花一定时间,所以如果你们能直接实现它就更好啦。(嘿嘿嘿)记住这一点,希望接下来的分享能给你们带来启发。

UX(User Experience用户体验)

动画

首先是动画。动画对一个优秀的应用来说是至关重要的,开发者也往往会先在这方面发力来提高应用质量。动画有很多种,像<blink>,<marquee>这种标签式的——对用户没什么卵用,但有些动画还是很重要的,它有助于用户感知当前的应用位置,特别是对于移动应用,天然的小屏幕,缺乏丰富的上下文。

我们刚推出React的时候,人们问得最多的问题之一就是,动画在React中的最佳实践是怎样的?这个问题确实很自然。我们看看React的开发模式——给出一个State A与State B,告诉React对应的State如何render,然后React就接管了从State A到State B之间的变换,开发者不需要关心React是如何做Dom Diff以及修改Dom的。然而动画关心的恰恰就是这个变换的过程。 目前动画在React上已经有很多优秀的组件与库,React transition Group React Motion,还有React Native里的Animated库。
1_1
(译者注:此处略去Ben安利Animated的过程,感兴趣的读者可以查阅ReactNative Animated动画详解

所以,我们打算在web版的React里实现Animated库。

手势

动画与手势是紧密相连的,而手势正是我们当前不好把控的地方。人们在构造应用的时候经常忽视手势的重要性,特别是移动应用上。事实上,手势的流畅度正是原生或者优秀应用与恶心应用之间最大的差距之一。

2_1

我们看个例子。这是苹果手机上的地图应用,看起来很简单,与它交互起来也很轻松。仔细分析下这个应用,我们会发现有大量的手势操作在里面。你可以

  • 用一个手指拖动地图
  • 用两个手指缩放地图
  • 可以点击大头针查看相关信息
  • 双击放大地图
  • 长按放置一个新的大头针

这些操作加起来,体验确实很优秀。但没有合适的代码抽象时,这个应用很难开发出来,事实上在web基本不可能用touchstart,touchmove,touchend开发出来,因为这不是我们想要的接口。我们需要的是一个基于它们的手势系统,可以推断用户的手势操作,预测用户的行为。所以我们的目标是做一个手势系统,有简单的组件API,而且是纯JS实现。React Native可以在iOS和Android上借用系统的能力,但我们不想考虑跨平台的问题,这样Web上也可以有良好的手势体验。

性能

关于用户体验的话题,我想讲的第三点是性能问题,这里指的是列表优化。有一些Web开发者可能疑惑了,为毛是列表?我想移动Web开发者应该有一些体会。在移动应用上,我们用到了大量的列表,通讯录、日历、通话记录,信息,照片展示,全都是一列东西。所以列表性能优化对于React也是很有意义的。这里我想讲三个技术点
3_1

窗口渲染(Windowing)

窗口渲染指的是只渲染在屏幕上的部分。这听起来很明显,为什么要浪费时间渲染不在屏幕上的东西呢?然而这活现在在React的模型下没那么简单。我们对此有做过一些抽象,然而性能效果都不尽人意。

分块渲染(Render In Thunks)

我们的第二个想法是,将列表内容分块渲染。当你在滚动一个列表的时候,一个新的列表项出现在屏幕上了,看看这个新项的复杂度,如果是个非常复杂的东西,比如一条Facebook的状态,有作者,内容,图片,视频,评论,点赞等等,几十个视图需要在屏幕上渲染,这可能50到100ms,此时滚动就开始变得不流畅,反应迟钝了。如果React可以只渲染这条状态的一部分,保持滚动流畅,然后再慢慢分帧渲染这条状态,这样就可以使应用持续保持响应了。

布局(Layout)

关于性能的第三点是布局。当我们用Chrome的Timeline剖析任何Web应用的时候,看到很多红色的小三角,鼠标移上去,显示着强制回流(Force Reflow)。当重复地改变元素样式,然后再去获取元素样式的时候,浏览器不得不及时地重新执行渲染算法,然后给出最新的元素渲染信息。React在这方面已经做得不错,你很难意外地创建一个这样的循环来消耗浏览器的性能,但还是有这种场景存在。

假设有一个组件,你希望根据组件的占用空间来做不同的展示,这时最好的选择,是渲染一个占位器,在componentDidMount的时候可以测量内容的宽高来决定最后的渲染结果,然后再次触发render来实现。当你希望根据渲染结果,比如文字宽度,来决定最终渲染的时候,总是不得不渲染两次。

我们的想法是,由React来管理布局如何?你们肯定觉得这想法很疯狂,我一开始也是这么觉得的。但仔细想想,这样做会带来什么改变:
4_1

  1. render()里获取布局信息。

    比如当文字宽度大于300px时,渲染A,否则渲染B。

  2. 避免不必要的回流问题

  3. 使得窗口渲染的实现简单得多

  4. 避免创建仅布局相关的元素

    当我们在Facebook Google的页面上审查元素时,能看到大量的div。有一些div有边框背景色,然后更多的div往往只是因为布局需要而创建的。它们不渲染任何东西,存在的意义就是把其它元素捆在一起。如果没有这个div,而子元素能保持在原来的位置上,那么渲染出来的结果是一样的。我在Facebook.com上做了统计,发现有60%的元素就是干这活的。它们不渲染任何东西,而浏览器还要对它们进行管理,处理它们的事件等等。如果我们能把这些元素去掉,显然可以使页面加速。

  5. 创建新的布局

    用css来布局页面有多痛苦,我相信大家都懂的。特别是使用浮动,绝对定位等,总是很难兼容各个浏览器地把元素放到我们期望的位置上。FLexbox布局就相对好多了,不过我们很多时候还在等各个浏览器支持某些特性,而且它也不是万能的,比如不支持Aspect Ratio布局等等。但是,如果我们掌握了布局信息,我们可以创建自己喜欢的布局组件,比如堆栈布局(stack layout)/栅格布局(grid layout)/瀑布流布局(Pinterest layout)

DX(Developer Experience开发者体验)

下一部分我想讲一讲开发者体验。之所以讲这个话题,是因为提高开发者体验,就可以减少开发者无谓的时间浪费,提高开发速度,有助于开发者专注开发出高质量的应用。

新项目体验

如果你足够幸运,你也许从来不需要从头开始构建一个React项目,因为公司里的React项目已经创建好了,正在正常运转。提到这点,是因为现在创建新项目是一个痛苦的体验。如果你想尝试最新的工具,你需要花时间搞定node npm gulp webpack babel等等一堆东西,此时你还没写出一行代码。你也许不需要这些玩意,比如React的玩具项目就没用到这些(除了一行用了babel即时转译的代码)但这些工具并不是无用的,相反,它们解决的都是很现实的问题,构建大型项目的时候往往离不开它们,然而同时我们失去了web的朴素性——创建一个HTML,用浏览器打开就可以用了,不用安装任何东西。

我们理想的开发模式是,只需要创建一个指向根页面的app.js,然后用react运行它,就可以直接打开浏览器看效果了。如果指定平台是ios或者android,可以打开对应的模拟器。而随着项目的逐渐发展,我们为了性能优化,提高扩展性等原因,可以慢慢地把上面列到的工具加进项目中,但它们不应该是启动新项目时的必须项。
目标:用一个文件快速构建原型,然后随时间慢慢增强应用
5_1

开发者工具

第二,是老生常谈的开发者工具。有许多工具我忍不住想安利一下:

  1. 官方出品的chrome/firefox的react-devtools插件
  2. 热加载(react-transform-hmr)
    修改文件,保存文件,浏览器或者模拟器就会自动更新页面,而不需要重新加载页面
  3. IDE(nuclide,deco)
    nuclide是facebook出品的IDE,而deco是最近在Hacker News上比较火的React Native IDE。这些IDE可以让你清晰的看到组件状态,修改样式时可以看到实时的效果,同时完全不需要退出IDE。

    以上这些工具都很棒,我们团队都很喜欢,请做出更多类似的东西,我们会尽我们所能提供帮助。

数据管理

7_1
第三个开发者体验的问题是数据管理。人们有很多种方法可以做数据管理,而大多数情况下都是从React内置的setState入手的,这是一个很好的起点。setState超级简单,一两行代码就可以了。它将数据都封装在了组件内部,这在一开始使得组件内部通信变得异常简单,但当你想复用这个组件的时候,麻烦就来了,你需要做额外的工作来保持数据的一致性。

所以当应用规模逐渐增长的时候,人们往往会转向FluxRedux等。这些方案将数据从组件中抽离,放置在中心化的存储结构中,这是一种很棒的实践,你可以随时随地从组件中访问这些数据。FluxRedux都没有提供服务端通信的解决方案,交给开发者自己实现。使用这些框架还有许多要预设的地方,比如dispatcher action creator等等。

第三种数据管理的方式,Relay,在Facebook内部就非常流行,目前开源社区对它的关注也在不断增加。Relay允许组件自由地获取自己需要的数据,而不是“通知server去获取数据,提供API,然后在数据中心拉取API,再填充到组件”。 基本上10行代码就可以搞定了,我们称之为Colocated Query。我们认为这玩意意义非凡,已经在Facebook内部用上了,不过如果没有一个支持GraphQL的server,relay就玩不转了,不幸的是目前大多数人都没有GraphQL Server。不过如果你有很多纯客户端数据需要管理的话,Relay也不能帮上太多忙,因为在服务端没有对应的副本。

这些数据管理的方式都很棒,我们的目标是找到结合这三种方案的最佳实践,配置简便同时能复用代码。 理想情况下,我们可以切换到任意一种模式进行开发,而代码复用是开发体验中很重要的一环。我们鼓励你在设计应用的时候,尽可能使自己的代码容易复用。可能是复用数据逻辑,也可能是复用UI,或者是把数据逻辑与UI放在同一个组件里复用。

代码复用

9_1

谈到代码复用,我想给大家看看Facebook第一个完全用React Native实现的APP,这是一个用来创建和管理Facebook广告的app,可以看出iOS与Android的界面很像,但是设计上都符合各自的系统规范,看起来像是原生的,而实际上它们有90%的代码是共用的。我们还有一个移动web版,它和App版共享一点点数据逻辑层的代码,完全不复用UI代码。但可以看到他们相似的基本特征与系统目标,同样的广告活动列表。

我们已经有ReactNative可以开发iOS和Android,如果再支持一些web版呢?这对你来说,并不是什么天翻地覆的变化,你不需要改变原有的工作流——拉取数据,设置img、span标签,填充文本,虽然像iOS和Android一样,并不能共享全部的代码,但为什么不复用基本的界面呢?就像图中一样,有iOS、Android、Web三个版本,看起来很相似,并且共享着90%的代码。

这只是一个idea,我知道你们都希望它真的存在,然而它目前仍然是镜花水月。这真的很有启发性,它能真正改变工程师的组织结构,与其将工程师分为iOS组、Android组、Web组,可以把他们合为一个团队,基本上看起来就像是3倍人力——我开始关心硅谷的人力问题了= =

今天的React

谈了这么多,我们有太多想法,该如何实现呢?
10_1

我们现在是一个超大的开源社区了,目前React的版本是0.14,在2013年时已经有用于生产环境的稳定版了,下周五(这里指2016年1月)我们即将发布下一个候选发布版本15.0。之所以叫15.0,是因为我们发现,之前发行的许多版本都已经可以用在生产环境上了,应该有个大于1.0的版本号了。大家已经习惯了React13,React14,现在可以称之为React15了。即将发行的版本主要解决的问题有:完整支持SVG标签,文字节点不再有span标签包裹,废弃<noscript>标签(组件返回null的时候出现),使用HTML注释代替。我们会更频繁地发布小版本,更快地增加新特性。同时,还有一次内部重构,废弃了react-id,现在审查元素也不会看到它们了,使得性能提高了10%(此处有掌声)

11_1
在2015年,我们有300个人给react贡献代码,600个人给react-native贡献代码,这么多人,估计这个会场都坐不下了。我们在Github上获得了36000个star,只是个虚荣的数字,我提到这个数字是因为我们想知道有多少开发者在使用React了,而Google可以告诉我们,已经有225,000个人安装了Chrome的react-devtools,这意味着成千上万人已经在用React构建应用了,这太令人兴奋了。不仅仅是数字,我们还有很多关于React的优秀项目,比如Redux、material-ui,react-routers,enzyme,解决了很多我们都没考虑过的问题。

正如我刚才所说,希望大家能从这次分享得到灵感,贡献更多鹅妹子樱(amazing)的项目,谢谢大家!

转载自AlloyTeam:http://www.alloyteam.com/2016/04/reactjs2016-what-lies-ahead/