How about a nice cup of React

落在深海 原文链接

接触 React 一年左右,期间在单页面、单页应用都有使用, 它极大地改变了我个人的前端开发方式。为方便快速出产品,闲暇之余也尝试写了点基础组件: react-component, react-image-cropperreact-touch-gallery, react-file-upload。也一直计划着写点心得总结什么的,迫于忙、浮躁,难静下心写东西,屡次作罢。这两天刚离职,决定把这篇总结补上。

在 React 之前,玩过一点点 Angular 跟 Backbone,Backbone 是比较轻量级 MVC,Angular 较重,它的指令、注入式写法, 较死板的规则,不够简洁的 API,诸多概念等等,最终只是被我当玩具折腾了下。由于接触到项目多数时间花在 view 的交互、事件、变化更新上,所以大多数情况还是选择熟悉的 jQuery,原因无非是:熟练,可控,最轻依赖,快速灵活。过程基本上是: 命名 DOM,给 DOM 加特效,取数据更新 DOM, 绑定事件到 DOM 等等。时间一久,问题就很明显了:即使多次尝试做不同层次的抽象分层,还是很乱,太频繁与 DOM 打交道,遇到问题不好排查,维护也很痛苦。如果能尽量少碰 DOM,以数据、逻辑导向来写 view 呢?

Github 上有 xx 步从 jQuery 到 Backbone, 就是通过一步步迭代,解释 Backbone 如何抽象分层,将数据、逻辑、事件、view 操作做分离,使得层级清晰,逻辑分明。可如果只为解决 view 层问题的话,是没必要引入过多概念和规则的,且 view 本身的问题,例如高复用性等也没有被解决。

React 带着变革前端开发的使命而来,声称专注 view 层,特点是组件式开发,有着简洁合理的 API,不错性能等优势。

说到组件式,大概包括了外部属性跟内部状态。比如电视盒子,对屏幕来说,只需要提供几种插口;内部构造对外是透明的,根据插口接入的不同,呈现截然不同的输出,屏幕也无需知道盒子内部的运作方式。实际上用 jQuery 时,大家也多多少少封装过一些『组件』,供外部使用,比如购物车 Counter,自定义播放器等,但并不会像 React 那样通通都是组件。在 React 里,组件包含 props(外部属性)跟 state(内部状态), 具体细节可以去看 React 官网。

初次对组件式思维赞叹的是评论的加载更多功能。一般用 jQuery 的话,思路是请求数据,组装 list DOM ,append 上去; 换做组件式思路呢?答案是数据驱动。评论的数据应该属于评论内部状态,那么加载更多调整内部状态就好了(不断练习这种数据导向的思维,合理设计 props 跟 state,对于通常项目需求,写起来就非常快了,同时也基本避开了对 DOM 的操作),React 帮你把状态的更新高效的反映到 DOM 更新。

逐渐对组件式开发轻车熟路,反过来也不断巩固组件化开发思维,于是开始真正信服 React 的 Learn once, write anywhere.

组件真的那么好么?

组件堆叠组合的方式让高复用变得简单,然而在开发中还是遇到了些问题:1. 刚上手很快就遇到组件如何通信的问题,看了 React 文档才弄明白;2. 在写 Dropdown 时,改变外部默认选中值并不会导致 Dropdown 选中值变化。当时头脑不清晰,折腾了半天,这个问题归纳为:state 依赖于 props 的初始值(该变化后也需向内传递), 而 state 也通过自身内部维护,这个问题有很多使用场景,这里内部维护是指 Dropdown 选中来改变 state。那么如何让 props 改变再来触发 state 呢,看了 React 生命周期才知道有 componentWillReceiveProps 这样的方法,也不得不赞叹 React 生命周期设计的周全,这个问题在后来用 Ember.js 写组件时同样也遇到了,只是实现稍有不同;3. 组件层级深,层层传递 props 到子组件很麻烦,React 提供了 context,使子组件方便的获取父组件链上下文 props;4. 组件的被动方法如何调用,例如点击按钮触发组件的操作?通过 refs 可以拿到组件实例,从而调用实例方法,而 findDOMNode 则能拿到 DOM 元素等等。不断有新问题涌出,问题也在一一被解决,React 之路进阶还在继续。

当然组件模式并不是只有 React 一家, Ember 2.0 弱化了 controller, 加入 component 的概念, Vue.js 也是组件的思路,甚至更轻量,简洁优雅。为什么选择 React ? 原因有几点:相比 Emberjs 这样的 MVC,React 轻量、概念少,简单清晰,高效的 DOM diff 算法保证了性能,只做 view 且做的足够好。Vue 是后起之秀,高性能,更简洁,十足野心要替代 React, 在前公司生产环境投入使用,遇到几个问题:1. 在 template 里用 computed 属性、method 甚至是 data 看起来傻傻分不清楚,component 里 data 跟 props 也差不多,协作的话需有团队约束。2. 看似比 JSX 片段清晰的 template,实际上却因语法导致引号、括号、字符串、方法调用等使用造成视觉混乱。3. 还是模板问题,指令必须依附 DOM,逻辑好不清晰(据说这点在2.0得到改善)。基本上都是关于 template,也不算太大问题。

有人说经过很多年发展,终于模板跟 js 逻辑分离了,React 一下子又倒退回去了。说出这言论的一定没用 React,当你真正体验 React 的『合并』后或许才能体会到它的方便之处。如果你也曾经历模板逻辑分离的不同时期,回头想想,分离真的那么好么?逻辑部分还好,而模板呢功能太弱,要做到精确控制输出很费力,而且脱离逻辑谈复用性也并不靠谱,真的是我们想要的么?React 的 JSX 用类 XML 的语法糖,使得可以通过 JS 语法来方便精确控制输出逻辑,再加上组件作用域的光环也显得十分合理。

总结下吧,React 带来了前所未有的开发体验,也引领了组件式开发的热潮,对于开发者来说,优势很多,例如:

  1. learn once, write everywhere.
  2. 模板跟逻辑在一起,逻辑精确方便的控制输出。
  3. 组件式开发思维,让开发者专注数据、逻辑。
  4. 简洁清晰的 API,较少的概念,易上手。
  5. 周边生态逐渐完善,开发者也很容易做出贡献。
  6. 社区活跃,库本身在 Facebook 及很多大厂使用,能力得到充分验证。

问题、疑惑及待解决:

  1. 方法普遍太长(各种编辑器补全插件可以有效解决)
  2. 生命周期的不同阶段需要弄清楚,不然会遇到些奇怪的问题。
  3. 组件化必然导致状态的零散,如何集中管理状态,又如何通知更新所有组件状态,可以去研究下 flux 跟 redux,但各有缺点。
  4. 模板跟逻辑在一起,更容易写不好,乱,对人要求不算低。
  5. 组件样式编写问题。

注意: 本文主观色彩较严重,细节并不考究,若有问题欢迎指出。

好吧,更多的,以后想到了再扯吧。