为什么我们用 React 而不是 Vue

为什么我们用 React 而不是 Vue

我们的产品 卡哇微社区 后台是用 React 编写的,而不是Vue,很多人曾经问我过:老刘哎,你们为啥不用vue呢,vue不香吗?

每次说起这个我都会想起第一次做技术调研时的场景,那个时候我还不了解前端,调研了 Vue/React/Angular 三个主流框架。得到的信息大概是这样的:

  1. Vue —— 简单易上手,但是模版复杂
  2. React —— 上手有门槛,但是灵活
  3. Ag/Ag2 —— 功能强大面面俱到,门槛最高

彼时我还只是一个前端新手,自然对 Vue 的简单易上手非常感冒。于是开始了第一周的 Vue 开发,结果是令人非常不愉快的(当然这和我没有认真看文档有关)。主要问题是 Vue 太需要看文档了,我要做的每一件事情,比如何循环渲染、如何现实对话框、如何自定义组建统统要看文档。虽然上手简单,但是我又懒得看文档导致我用 Vue 的过程一波三折,一个简单的 弹框新建 功能写了好久。

极度的挫败感让我重新回到了 React 的怀抱,其实那时候我对 React 是特别排斥的,大概是因为 React 又多了 jsx 这玩意,添加了我的负担。然而在我写了一点 React 之后发现,React简直棒极了!因为它是一个程序员的工具!

上手 React 其实并没有网上说的那些门槛,写一个 Hello 大概这样(如果说Vue 1分钟上手,那么 React 3分钟也可以上手,都是分钟级的实际并没有太大差别):

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

唯一一个需要理解的概念是组件:Component,要知道这其实是非常面向成员的。Component 就是一,一生二,二生三,三生万物,千变万化,所有的功能都从此开始。对于 React 来说,只需要看一页的文档就是关于 Component 的文档。

真的!所有的功能都从次开始。

如果用 Vue 此时我肯定又在研究写模版,看文档或者在记 Vue 特有的模版语法,用 Vue 内置的模式来绑定数据。但是在 React 你只需要写 Code,并按你所想的那样做就行了,React是极其灵活的。

很多人觉得 React 复杂往往还有一部分原因是 Redux。Redux/Flux 是 React上的一套标准的状态管理器。何谓状态管理?从泛 MVC 的角度看就是Model/Controller。

如果你看过 FB 早期的关于 Flux 的那个视频就知道他们最早搞 Flux 是为了解决复杂UI的状态不一致的问题。这个问题大概是这样的,假如我有两个页面,分别是帖子列表和帖子详情,如果我在帖子详情那里点了赞,那么在帖子列表那里也应该是点赞的状态。这就是状态一致的问题,这个问题有很多种解法。

在 MVC 架构中,帖子列表和帖子详情是两个不同的 Model,为了同步状态无论是在哪个页面了点了赞都要修改自身的同时还要修改另一个页面的状态(如果我们再引入第三个页面状态管理就变得更复杂)。Flux 的做法是引入一个中间层,现在我们不直接修改列表和详情的状态了,我们添加一个 Store/Action 系统,当点赞的时候发送一个 Action 给所有的 Store,Store 自己按需修改自己。这个系统其实对于绝大部分的比较简单的UI系统都是多余的,我们根本没有必要为了更新一个小小的UI就去写一个 Action,既麻烦又无聊。

Vue 就没有这种烦恼,Vue内置了自己的状态管理。Vue的方案是数据绑定+EventBus,这个其实还是MVC的思路,对于上面的那个问题,Vue是使用EventBus 来解决的。对于大部分不需要同步状态的场景用数据绑定就行了。

PS:其实还有第三种解法,既然要同步各个页面的状态,为啥不让各个页面共享同一个 Entity 呢?这种解法个人觉得有自己的局限性和适用场景,比如 SPA 应用中的用户数据比较适合这样做,但是帖子并不适合。现在比较推崇的 Entity Pattern 就把这种做法发挥到了极致,所有的页面使用的 Entity 都是同一个 Entity,这个系统会导致一个非常愚蠢的问题,如果用户在网站不断的浏览数据就会导致页面加载越来越多的 Entity,而页面却无法删除那些已经不再被使用的 Entity,有人还为此专门写了 Entity 的引用计数系统,个人觉得这把简单的事情做复杂了。

现在回到 React, 由于 Redux 的枯燥乏味我们也是果断放弃了 Redux。我们最终自己搞了一个架构,核心组建是一个叫 baobab 的 js 库,它实现了观察者模式,基于它可以实现类似 Vue 的数据绑定效果。对于上面那种特殊的数据同步问题,我也采用 EventBus 模式,如果真的需要同步各个页面数据的时候再发消息解决。

所以你看,状态管理本身对我们选择谁并没有太的影响。我一直觉得状态管理是自己的事而不是UI框架的事,虽然说 Vue 内置了状态管理框架但是它也约束了你,无法做出其它的选择。而我们现在的状态管理还吸收了 Vue 的优点。

另外,对于后台管理系统,看起来很复杂,但是实际上后天管理系统的各个模块都是自包含的,很少会有互相依赖的情况。比如我们的后台:

这里的好处在于,我们几乎不会产生任何状态同步的问题,每一个模块都是自包含的,比如帖子管理和用户管理八竿子打不着。我们只要做最简单的数据绑定就好了。

关于架构,我们大概是这样的:

➜  src git:(master) tree -L 2 .
.
├── index.css
├── index.js
├── model
│   └── state.js
├── service
│   ├── api
│   └── utils
├── shared
│   ├── charts
│   ├── comps
│   ├── draft
│   ├── icons
│   └── images
└── views
    ├── apps
    ├── kawa.css
    ├── kawa.js
    └── user

主要是 model/service/view/shared 三个目录,model 中就一个文件 state.js 定义了我们的 baobab 树:

const state = {
    // meta-data
    token: {
        value: undefined,
        error: undefined,
        loading: false,
    }, 

    users: {
        loaded: false,
        error: undefined,
        data: [],
        total: 0,
    },

    posts: {
        loaded: false,
        error: undefined,
        data: [],
        total: 0,
    },
    //... 省略
}

service 中就是 API 和 一些处理业务的方法,shared 目录存放共享的组件和工具,views 目录主要存放页面。

为什么国内很多人会觉得 Vue 比 React 简单易上手呢?我觉得这部分人中有很大一部分人是写 HTML 出身的,HTML 和 Vue 的模板系统对他们来说有天然的亲昵关系。但是对于有移动开发、桌面开发经验的同学来说,理解 Component 更为容易,并且更青睐于这种灵活的系统。

对于状态管理,我觉得没必要被 Vue 或 Redux/Flux 束缚住自己的手脚。作为一个合格的研发,自己选择适合自己的架构不是最基本的看家本领吗?

最近开通了自己的微信公众号: 独墅湖写码,感兴趣的同学可以关注下,这个号主要分享自己的创业感想和一些技术文章。

江天一色无纤尘,独墅湖中孤月轮。

编辑于 01-05

文章被以下专栏收录