我们为什么需要 React?

7月13号更新, 其实我想问的不是angular跟react哪个好,哪个不好. 我想问的是,react的代码相对繁琐,那么在繁琐为代价的前提下为我们解决了哪些痛点?最近在学习react, react概念虽然简单,本身使用这个库也不复杂. 但是学到后面一点冒出了三个东西: Flux,Reflux,Redux; 加上这三个东西,我就觉得react一点都不简单. 因为react学的还不够深入,所以还没有意识到很多问题. 但是既然出现了Flux,Reflux,Redux,存在肯定有存在的理由, 那就证…
关注者
1,415
被浏览
123,356
在此声明一下,只是想通过技术角度去评价框架,并无意去指责或者去嘲讽其它框架,如某些言论表达得不恰当,请私我,我可删除。对于无意义的漫骂或指责,表示不接受也不回复。

关于React的问题,我有几点要说:

1、React确实存在组件嵌套的性能问题,但是可以通过Redux去解耦以达到目的
2、对于引入immutable / reselect 对于大部分并不是必需品,组件粒度越细,state使用得越少,需要引入shouldComponentUpdate的情况越少,其实在项目中真正有用到它们的有多少呢?
3、React的中大型项目上的应用并不是太大的问题,国内有Ant.design已经在大量的蚂蚁金融平台和或各类内部平台上使用,尽管Vue也有,但只是实验版本,也并没有再去升级。 在国外:faceBook算大型应用吗?它本身已经就应用了React 16 Alpha 版本,以身试坑,这样算得上 React 在大型应用上有问题吗?
4、React是有门槛的,确实没有Mv**那么快让人容易接受,需要有一定的JS基础和开发经验。
5、对于理解Redux,有些人需要些更多的时间去理解,有些人却能够在短时间快速掌握,同样是在中小型应用中,确实是有些繁琐,可是我们同样可以通过Redux-Actions去简化这些繁琐。最简的Redux-actions写法如下:

Action:
let increment = createAction('INCREMENT', amount => amount);
Reducer
const reducer = handleActions({
  [increment]: (state, action) => ({
    counter: state.counter + action.payload
  })
}, { counter: 0 });

1、action.playload = amount
2、state.counter 来自于 store.counter

注: 在中小型应用中,这么写法,算很复杂吗?难以理解吗?推荐您往下读读我对Redux的理解。


再一次题外话:很认可Vue本身带来高效率的开发和很低的学习曲线,并认可作者的努力,也觉得Vue未来能够给大家带来更多优秀的特性,但是我们不能够忽略Vue及Mvvm本身存在的问题,同时也是希望我的分享能够给大家带来个人对框架的体验。


我是从0.12版本开始使用Vue的,大概使用7个月+吧。开发的项目本身更多的是通过自定义控件,让用户更快的构建自己的游戏管理,已经接入了数十款游戏,游戏本身给公司带来的收入达到数亿计。我不敢妄自菲薄称该项目是大型项目,仅仅只是一个中小型级别的项目,我来说说在这项目中使用Vue带给我的体验。

1、Vue确实简单,文档非常清晰亲民,可是API数量太多,数次遇到的问题都是因为对API的不熟悉,同时概念太多,尽管完成了项目,但是很多地方逻辑处理得不是很让人舒服

2、翻开代码,我依然看到我不成熟地使用inherit特性所导致继承组件带来更多无意义的变量,常常因为一个变量的变化,常常影响子组件的属性,直到API官网出现了最佳实践,方知自己错误的实践。

3、满屏的的v-mode / $watch / $on / $emit / $dispatch / $set / this.var 让我们调试问题变得更复杂,因为我不知道究竟断点该断在哪个位置,还是在视图才能够更快的找出问题,因为我一开始觉得使用它们是更轻松、更舒服的方式。我相信作者也敏锐的发现了这个问题,把$dispatch在2.0给移除掉了。

4、更为神奇的是,我在文本框以及它的父组件使用v-model时,发现输入中文,发现中英文同时出现文本框里,我发现这个问题是在于我使用0.12.6 之后的版本才会出现,而0.12.6本身并不会有这样的问题,当然最后我使用了 v-on keyup 来解决了。我相信是我的使用姿势不太正确。

5、Vue.Compnent / Vue.Extend / ViewModel 它们的 options 重叠相同的部分太多,在项目中每个人都有自己喜欢使用的方式,假如不合理使用,可能导致,各种data不合理的出现在不同的位置。

Vue确实是一个优秀的新秀,使用它,你并不需要担心有比较严重的bug或者性能问题,但是你仍然要担心的是在大量的删改API情况下,我如何从0.12迁移到1.x,2.0, 我有想过,我被1.x那些优异的API所感到新奇和惊喜,但是大量地使用 inherit 导致更新起来逻辑调整更困难了。

相信作者对于JSX,还是有一定相法的,不然也不会去在2.0引入JSX。而恰恰地,存在一个问题,框架本身带来的可选项太多,我们如何快速的识别它们带来的副作用,让我们如何提供更优雅的方式去使用框架。那么同样的问题也存在了,究竟我们是选择JSX 还是 template呢?

而Vue 2.0删改了哪些API呢?我很无聊地去数了下,大概有30+的API,我例举下些可能大家可能曾经会用到的部分API:

Vue:(删除)
Vue.elementDirective / Vue.partial / options.replace /

生命周期:(更名)
init => beforeCreate
ready => mounted ?
compiled => mounted?

options(删除)
partial / elementDirectives / events

Dom(删除)
vm. $els / vm.$set / vm.$get / vm.$delete / vm.$dispatch / vm.$boradcast
vm.$appendTo / vm.$before / vm.$after / vm.$remove

Directive(删除)
v-ref / v-el

我们相信作者删除它们是为了简化API的负担,可是这些API,是否又能够轻松的从项目中迁移呢?特别是DOM,相信大家自有定论。


同时React也存在,使用它周围哪些库更轻松更简便更合理地开发呢?可幸好,它们是可选项,而 Redux也仅有2K代码量,想要重新实现它带来的思想是一件很轻松的事。

使用React,让我感受到组件本身带来强内聚,搭积木式的组装体验,通过 render 函数更直观的看到 DOM 结构,这也是为什么我使用 React 的原因。

我并不排斥任何新框架,新事物,对于任何框架我很欣赏也很钦佩框架作者的技术能力,但是我仍然不想忽视框架本身存在的问题,因为没有完美的框架,只有适合的应用场景,选择自己更适合的,不是吗?


====================================
题主乱带节奏,带偏一帮老司机飚车飚错了方向,我就我有限的经验聊聊React解决什么痛点,以及我们为什么需要它吧。

在此之前,我先做个声明:

框架都是为了提供某类开发场景而生的,性能只是加分项,再厉害的框架也牛不过原生撸码!


现在主流的框架(主要以React/Vue/Angular为背景)都主要以有限数据状态机来解决复杂的交互应用场景、编写可控可复用的代码以及开发效率问题。而它们所谓的繁琐是相对于应用场景和人的。

题主说到React繁琐,指的是他并没有理解Flux/ReFlux/Redux为什么要撸那么多代码来实现原来仅仅只需要$.ajax就可以实现的数据交换以及组件间通讯问题。

其实我恰恰认为它们(Flux/ReFlux/Redux)并没有 优雅地解决数据交换以及组件间通讯(不喜勿喷),在我的项目中我已经拒绝再去使用它们,那样React变得更轻量了?

可我们依然要面临组件间通讯繁琐的问题:

1、通过父组件通过给子组件传递函数到Props,重绘父组件达到更新兄弟或兄弟的子孙组件达到目的。但是,重绘父组件会导致其所有无需更新子组件重绘,同时可能导致被动更新的子组件某些与props有关联的state 被更新(state丢失)。只能通过ShouldComponentUpdate 者componentWillReceiveProps去解决此类问题。对于孙子以下的组件更新更加繁琐及麻烦。

2、通过一个中转容器去解决跨组件通讯问题(例如EventEmit/Redux等),但EventEmit却没有更好地解决数据与视图分离,以及Event本身带来的闭包、隐含逻辑依赖关系和时序问题(通俗的说,项目大了,不同对象的不同的事件名称、参数和调用关系变得很乱)需要有一个很合理的解决方案。

而我们,只不过想把某些个数据发送到指定的组件里执行。而我认为吸取Event/Redux等的经验。我们可以这么做:

1、提供一个数据容器,所有数据都直接发送到该容器,这样我们可以轻松做到Redux的可预测和可回溯。
2、关联组件所需的数据到该数据容器。
3、约束数据发送时,接收组件的父级及子级不允许被更新(很多人在做组件设计时,父组件接收数据A的KEY1,KEY2,而自己接收数据A的KEY2和KEY3,这样是错误的设计,应该把接收数据A的KEY1,KEY2的内容拆成一个子组件接收)

等等,这不是和Redux差不多吗?


NO, NO, NO, NO,请耐心听我说完。


差异在于:


1、我们只发送数据,不需要定义ActionType等等


dispatch({ key1, key2})

dispatch({ key1, key2}, reducer)


注:reducer是可选项。


这样我们便可以很轻松地,将它们封装起来


dispatchUser = paramter => {
// promise.all(login, xx).then(..)
// fetch(json).then(..)

// dispatch(json, state => object.assign({}, state, json))
dispatch(json)
}





2、配置接收数据的组件

connect( state => ({ key1, key2 })(componentA)

class componentA {
getStore(state) {
this.setState( { key1: state.key })
}
}



注:假如你想默认直接更新,稍微包装一下就实现自动setState。


具体代码我最近还在开撸了,撸好了,再告诉大家。

当然使用Redux,可以借助Redux-Actions去简化我们的实现。具体可看:GitHub - acdlite/redux-actions: Flux Standard Action utilities for Redux.

选择React:

1、我们可以使用最简单的JSX方式去封装我们的组件,我们只需要关注我们需要接收什么数据,以及展现什么内容, <Component A={} B={} /> 多么直观啊

2、只要熟练JS,就能够很轻松实现绝大多数模板语法的内容

3、因为API足够少,我们有更灵活的发挥空间

4、开发环境下,足够丰富的错误提醒

5、React版本迭代迁移,工作量并不大,有迁移提醒,API删改少量且迁移成本低

6、不会引入大量的概念到React库里,保持纯净,其它周边库都是可选项。

也有人质疑JSX,写起来不是那么的好看和直观,其实写多了,你会逐步体验到它带来的好处。例如分支判断可以拆个无状态组件等等。

未来可能会有更多优秀的框架,但目前,选择React仍旧是一个不错的选择,不排斥Vue,但是 API 不断的删改,引入的概念这么多,如何根据这些概念给出一个最佳实践到项目中到团队中呢?这又是一个新的问题

题外话:

假如您只是一个营销类的推广页面,仅仅只有轮播、几个文本框的表单的极浅交互,我还是推荐大伙使用原生 / zepto / jQuery之流。

假如您很在意体积,计较网络环境(2G/3G)等,可以使用服务器端渲染或者无阻塞UI(即添加占位符),使用带有GZIP的CDN,React各类库绝对能够在100K以内,假如超过,建议您使用按需加载。我相信您的服务器应该会添加有304/ETAG之类的缓存。

对于中大型项目,React确实是优良之选,当然也可以尝试Vue去迭代中小型项目。

=====================================================================
做为一个在从Angular到Vue, 最后选择React,并有实际项目经验的人告诉你。React我们需要它。

框架都只是为了开发效率和良好地组织项目代码,并不完全是为性能而生!
框架都只是为了开发效率和良好地组织项目代码,并不完全是为性能而生!
框架都只是为了开发效率和良好地组织项目代码,并不完全是为性能而生!


对于只会Copy/Paste的人,很好奇,他如何很好的维护那粪池?

Angular1.x 那些丑陋的特性,其实可以用ES6 或者 Typescript 进行二次语法包装,一样能够写得很漂亮的,隐藏很多让人无奈的细节。具体可以看:GitHub - ulfryk/angular-typescript: TypeScript 1.7 annotations (decorators) for AngularJS 1.x

这些仅仅只是有限的包装,你可能还需要包装更多更多的特性,不过这样真的好吗?

Angular 2.0.0 rc.4 (目前确认的最新版本) 已经酝酿了一年多了,语法几乎完全脱离了1.x版本。它似乎要把目前主流框架和特性都要集合到一块,如vdom、rxjs、typescript等等,源码模块引入了rollup去打包框架代码,业务代码依然是webpack。 然后我们默默地打开一下它的API文档,数百个API指令(请容许我夸张地虚报了个数字),如此大而全的框架,让人唏嘘不已。依然延续了1.x的繁琐复杂的语法,当然我们不能否认它们的一锅端设计,只不过适用的场景实在是有局限性,Ionic2这个Hybird端的老搭旧已经率先同步了。

尽管Typescript强健了我的代码,提升了我的开发效率;
尽管Rx革新了我的数据流,完美地封装我代码中那些不完美的代码逻辑

但是... 我依然没有办法再去学习这几百个API。

Vue相当不错,从一开始是一个简化版的Angular1.x,一年内从0.x 一直 飚升到 2.x ,作者一人撑起了80%+的生态,几乎覆盖现在主流的特性和小库。性能一直号称业界姣姣者。

等等,我们好像忽略了什么?

Vue 1.x 到 2.x 开始阉割大量API和模板语法。让一直追随他的小粉丝的我,开始懵笔了,我的Vue项目已经开始准备1.3,1.4的功能开发了,而我却只能使用0.x 看着别人快乐地用着1.x, 2.x 撸啊撸。

看着作者愉快地将某些个模板、某些个生命周期、某些个事件等等语法一而三,再而三地不断地改啊改啊的,还能愉快地跟得上这股风么?

与此同时Vue开始在2.x引入JSX的语法, 开始有点走Angular2小邪路,对于某些新人来说,我开心地时候想用JSX,不开心地时候,我喜欢用Template语法。这样的可选项是否合适呢

不得不说,Vue的生态、文档、性能等等各方面都都是业界的姣姣者,只可惜Vue只适合中小型项目的开发,已经开发够快,够稳定,概念够新,适合快速迭代的项目,但是对于中大型项目需要的是稳定....

修正一下,有人说vue2.x哪里支持JSX,先晒晒作者微博上的图(侵删):


看完上图是不是感觉和React相似度已经60%+了?当然还有*.vue/vue.component,是否作者是考虑让用户安稳的过渡到JSX?还是维护JSX和Template呢?那么最佳实践是什么呢?


React 是唯一一个让我真正体验到编写代码快感和舒适感。(尽管在此之前我很排斥JSX)

简约的语法,轻量的API,组织代码时的稳健,时时刻刻让我爽到溜起....

怎么简约轻量?可以看这里多个主流框架的语法对比:Front-end Hyperpolyglot

稳定的API,每次升级都是在强化和优化,相当少少少少量的API更新,即将废弃的语法,都会有警告提示,让我们更快的升级架构。

flux/reflux/redux 不仅仅只能用在React,也能用在Vue/Angular等等框架,仅仅只是一个数据流思想,您选择性地使用。

其实概念很清晰,举个Apple云很简单的例子来形容Redux:

我们的设备(Iphone/Ipad/Mac)的照片、文档等信息,都发送到云端。而我们关联云端的设备,当云端有数据更新,就会自动更新到有关联的设备或应用里。

而我们所说的Action 就是我们点击数据发送云端的指令;

而我们所说的Reducer就是接口,我们需要上传照片和文档,都需要转化到 成云端可以接收的数据格式。比如图片,需要转成二进制等等。

而云端就是我们所说的Store,存储了数据,很自然的,我们可以在云端查看数据上传历史,还原某一条数据历史等等,当然更多可以想像的功能,都可以在云端实现。

而我们需要实现React-Redux / Vue-Redux / Angular-Reudx 等等给到给到各个设备接收数据。

例如React的Connect,代码连接到云端接收数据并更新到组件。

React/Redux并不是没有坑:

1、setState 大量数据时(如700多条的列表),会有点点卡顿,当然我们可以通过优化得到解决
2、父组件更新某个子组件数据时,需要父组件重新组织,会导致其它子组件重新组装,虽然有vdom,但是这样显得不那么人性化。而且某个子组件内部有某些个state需要保持时,会丢失。需要shouldComponentUpdate..,当然你可以把组件的数据state=》子组件的props设计得更浅一些,至多2-3层,使用 redux,只connect具体需要更新数据的组件,粒度越细越好,保证单个state只更新到一个组件,这样还能带来易组装的好处。当然粒度越细,自然代码量也上来了,你也可以采用 stateless(无状态)组件去简化代码。各中取舍,取决于您的设计。
3、React-Redux经常在更新时,会产生过渡使用的问题,比如说父组件和子组件都connect,结果会导致第2点所说的状态丢失和重复render问题,还会有数据穿透的问题,因为connect只比较一层state。这时引入immutable能够带来较好的效果,不过个人认为完全没有这必要。已经有大量大神使用Event的方式去解决此类问题。而我,正在考虑撸个类似于Redux的方案。

总得来说,你需要React,它并不复杂,而是你听到的噪声太多。

对于大型项目,推荐 Webpac 2 来构建业务代码, Rollup 来打包你的小轮子。使用Rx优化你的数据流。Typescript强健你的代码,提升你的开发效率(头一周可能会有些痛苦)。但在此之后的收益是非常高的

对于中小型项目,推荐React/Redux/React-Router来构建你的代码

不要担心体积,因为CDN都有GZIP,能够压到原体积最高22%比例。
不要担心打包慢,因为通过优化 webpack,开发环境全量打包能快到 5秒, 生产环境能快到12秒。(vendor 5m 业务代码2m多)
不要担心噪声多,正因为如此,你的提升才会变得更快。
不要担心性能问题,因为90%+的场景下,你并不需要考虑性能问题。
不要开发效率问题,前人种树,后人乘凉的感受,会让你更舒适。

不要说React复杂,因为比起Angular、Vue要简单些。只不过没有更好的最佳实践和文档,所以你迷失了。

React 有 Flux/Reflux /Redux ,你只需要选择 Redux,Vue也同样有Vuex
React 需要 webpack / es6 等, Vue也同样需要webpack / es6,只是有它有 Vue-cli架手脚,但是React也有各种boilerplate。
比如:GitHub - mxstbr/react-boilerplate: A highly scalable, offline-first foundation with the best developer experience and a focus on performance and best practices.

再比如最新的 webpack 2 / React hot Loader 3 boilerplate: GitHub - ctrlplusb/react-universally: An ultra low dependency node v6 universal react boilerplate with an amazing dev experience.


请Vue/Angular粉不要骂我,我就照我的经历说,有什么说得不对,还望纠正。