Meteor 和 React 非常适合联合使用。两者的一个匹配特点就是数据的自动响应 - Reactivity。这种 响应式编程 避免了使用者再写代码来跟踪变量更新的情形,所以代码会更加简洁易维护。
下面简单对比一下 Meteor 与其他框架或者架构。
REST
不同于大多数传统架构,Meteor 没有采用 RESTful 的后端。Meteor 的客户端和服务器之间的数据交流是基于 Publish-subscribe 模式。REST API 挺消耗资源的,特别是在移动应用盛行的时代,客户端需要更频繁的存取数据,所以现在一个趋势是用Restless 架构,例如使用 WebSocket。不过 REST、SOAP 和 WebSocket 都有各自的应用场景。
Meteor 采用自己开发的一套基于 WebSocket 的简单协议 - DDP。基本上就是利用 WebSocket 传递 JSON 消息。DDP 有各种主流平台、语言的实现。支持列表见这里。所以也可以把 Meteor 仅仅当做后端服务来使用。
Meteor 就是基于以上描述的一个实时框架。所以能够做到以下三个特点:
-
Database Everywhere 前后端都可以直接操作数据库里的数据
-
Latency Compensation 就是 Relay 的 Optimistic Update
-
Full Stack Reactivity. 从数据库到模板,所有层面实时响应、自动更新
Flux
Flux 的核心概念是单向数据流,利用观察者模式保证数据源只来自于一个地方。
如上图。Flux 主要由三部分: Dispatcher, Store 和 View (React Components) 组成。
Action (或者叫 Action Creator) 是 Dispatcher 的辅助函数,主要是用来描述由 View 产生的用户互动或者其他触发事件。Action Creator 会打包用户互动来生成对象,可以看做是 Flux 的第四部分。
Dispatcher 类似一个中央集线器,由一堆 Store 的回调函数组成。
Store 负责保存应用的状态和逻辑,在其外部的代码是不涉及数据管理的;它自己也不产生数据,只能从外部获得新数据。Store 对 Action 进行反馈,然后发出一个数据状态改变的事件。Controller-View 监听事件,一旦触发就从 Store 获取相应数据。这样就能够保证数据的单向流动,使逻辑更简单。
Meteor 完全可以作为一种 Flux 的实现。例如使用 FlowRouter 作为 Dispatcher,MiniMongo 作为 Store。这样可以为 React 带来很好的数据和逻辑状态的管理;反过来,React 也可以为 Meteor 带来前端模块化,单向数据流模式,使代码更少且更好维护;另外 React 的 Virtual Dom 机制也为会 Meteor 前端渲染带来性能上的提高。所以我说他们是 Naturally Fit。
上图就是一个典型的 React Meteor App。个人感觉好像 Flux 更多是面向 Chat Based App,所以没有涉及到 routing。在 Meteor,很多时候 Router 其实是一个天然的 Dispatcher。而 Meteor 客户端自带的 MiniMongo 可以作为 Store。对于 View,如图中可以使用一个父组件来监听数据的变化,子组件负责界面渲染和互动。另外一个方案是使用高阶组件 (Higher Order Components) HOC 来包裹 UI 组件。高阶组件负责数据查询,子组件负责渲染等。在简单情况下,单个组件就可以了,Controller-View 可以和 UI 渲染在一个 Component 里。如果程序复杂,也可以使用 Meteor 的 Tracker.autorun 来建立一个独立的 Store。已经有人按照 Flux 的方式把 Facebook 的 Dispatcher 再包装为这个 Meteor 包 Github Repo。不过我认为这样做反而把简单问题复杂化了。也或许我遇到的问题还不够复杂。
Relay and GraphQL
Meteor 还没有类似 GraphQL 的包。不过据说正在开发类似的东西,甚至兼容 SQL 数据库。现在 Meteor 官方只支持 MongoDB。
对于 Relay,其实 Meteor 的 Meteor.subscribe 和 MiniMongo 做着类似的事情。下面对比 Meteor 和 Relay 的三个特点
-
Declarative Relay 不使用命令式的 API 来进行数据通信,而使用 GraphQL 申明数据需求,自动获取数据。 在 Meteor,如果使用 ReactMeteorData Mixin,可以获得同样的效果。getMeteorData 是一个 reactive computation,所以每次具有响应性的数据变化后,这个函数会被自动调用,再次获得数据。详情参见 这里。
-
Colocation 数据查询和 View 在一起,这样更容易理解和调试程序。Relay 还能聚集查询来提高请求数据的效率。对于 Meteor,前面提到的 ReactMeteorData Mixin 本来就是在 React 的 Component 里,所以也具有 Relay 的托管特点。
-
Mutations Relay 允许通过 GraphQL 在客户端和服务器端修改数据,并且自动做到数据的一致性,乐观更新 (Optimistic Update)。Meteor 的 MiniMongo 也具有这些特征。前面在 REST 部分提到的 Meteor 三个特点,Database Everywhere 和 Full Stack Reactivity 就是指在前后端存取数据,自动保持数据的一致性;而 Latency Compensation 其实就是 Optimistic Update。另外从 这篇文章 看起来,Relay 在数据的 Reactive 方面做得还不够,前后端都还要写一些数据的更新逻辑,甚至得通过 polling 来达到数据的实时更新。
小结
随着 Relay 和 GraphQL 的发布,感觉 Facebook 正在开发和 Meteor 同类型的前后端完整框架,而不是仅仅局限于前端 View。
其实 Facebook 没有发明任何新概念,只是把很多传统的软件开发实践用到了前端领域。随着移动应用的广泛传播和前端开发的复杂化,React 生逢其时,把前端工程化向前推了一步。
Disclaimer: 对于 Relay 我没有实际经验,都是通过 Facebook 的文档来了解,如果理解有偏差,欢迎纠正讨论。