作者:Jack Scott

原文(英语) 国内网可能访问不到……大致翻译如下:

本文主要分析了一下我们过去为什么需要 Redux,而为什么以后又不再需要了。

Goodbye Redux

在过去的几年里,互联网技术已经转向用前端 JavaScript 框架来实现网站和手机应用,以达到更好的用户体验。这非常棒 🔥 ,我个人很欣赏这些框架提供的灵活性。

但是灵活得是否有些过头了……

为了能更好地理解这个问题,让我们把时钟拨回到 JavaScript 框架出现以前,看看我们是怎么开发应用的。

⏳ JavaScript 以前的大陆 A Land Before JavaScript…

在前几个前端框架(最值得注意的是AngularJS、Backbone和Ember)出现之前,我们只是在服务器上渲染模板,然后将完整的HTML页面发送到浏览器。当时流行的框架包括:

sf, django, rails

  • Django (Python)——2005年7月21日发布 ~13 年前
  • Ruby on Rails —— 2005年12月13日发布 ~13 年前
  • Symphony (PHP) —— 2005年10月22日发布 ~13 年前

这些框架主要是围绕了 MVC 概念也就是 Model-View-Controller 来开发的,Model 表示数据的模型,View 表示怎么显示这些数据,而 Controller 则连接这两部分。

我的意思是说,这其中也有 JavaScript,但我们更多的时候是在说 jQuery 做的滑动条和一些完全没必要的动态网页效果

在这些框架上编写的应用有一些问题,但总得来说还不错,直到有一天 Ryan Dahl 有了一个很棒的主意,他开发了第一版的 Node.js,可以让开发人员写服务端程序,而不止是用 JavaScript 做些愚蠢的动画。

  • Node.js ——2009年5月27日发布 ~9 年前

猛然间人们似乎看到了 JavaScript 的无限可能性,用一丁点儿的代码就能做很多事儿,这充分打开了其他开发人员的想象力,人们不仅创建更多强大的 Node.js 工具,还开始创建有趣的前端框架,在接下来的几年里,JavaScript 就象滚雪球一样高速发展起来:

AngularJS, Backbone.js, Ember.js

  • Express.js(后端)——2010年11月16日发布 ~8 年前
  • Backbone.js(前端)——2010年10月12日发布 ~8 年前
  • AngularJS(前端)——2010年10月20日发布 ~8 年前
  • Ember.js(前端)——2011年12月8日发布 ~8 年前

这就开始了应用开发模式的重大转变。之前由服务端直接处理的 MVC 模式被分拆为两部分:一个服务端的 MC 和一个客户端的 V(MC),客户端使用的就是上述的前端框架。在早期的这些框架中,还包含 Model 和 Controller 层在 View 中。两份 Model 和 Controller,前端也有一份 MC,这样看来是要写更多的代码了。

🤦‍ 脸书有个头疼的问题 Facebook Had A Problem

正当所有人开心地使用上述方案的时候,Facebook 来了,随着它的迅速崛起,Facebook 变成了最大的网页应用,而为了解决页头上即时消息的数量显示问题(实际上这个小问题在海量用户使用的场景下是比较复杂的),旧的方案也并不能很好地应对……

Facebook head aches

于是他们推出了 React:

  • React(前端) ——2013年 三月发布 ~5 年前

而 React 只管 View 层,于是又有了 Flux,之后是 Redux(Redo Flux),有兴趣了解详情的可以看这个视频:

Youku视频 QQ视频

🍐 ……于是这东西变得象个鸭梨 …Then Things Started to Go Pear Shaped

Redux 的工作方式是把一个应用中几乎所有的动态信息都保存在一个 JavaScript 对象中。这样不管你在应用的哪个地方看到的数据都来自同一个地方,也就能保持一致,这样也就解决了 Facebook 所头疼的问题。

于是突然又来了一种新框架:React + Redux 解决方案,Facebook 用它来解决问题,而从此以后所有人都过上了幸福的生活……对吗?

✋ 不尽然 Not quite.

问题在于人们(包括我)开始用一个对象保存所有信息,其中的每一部分都是由服务端获得,没错这可以保证数据的及时更新,但同时也存在 3 个缺点:

  1. 这需要大量的多余的代码才能很好地运行,这很浪费时间。
  2. 因为所有代码放在一处,这可能带来“旧数据”的问题,也就是说你可能在应用中见到一些来自之前状态的不想要的数据。
  3. 对于新的开发人员学习曲线太高,继而使得前端Web开发很难被新的开发人员采用。

我们有一个向用户显示数据的相对简单的老式 MVC 框架应用,其中也就是几个简单的模板,在2005年,我们成功地将它转换为一个单页面应用,它的前端代码通常是后端代码的 10 倍。例如:我最近开发了一个简单的应用,然后我用 WakaTime 来衡量我在编码上的耗时情况,以下是测量结果:

  • React Redux 前端代码库—— 32 小时.
  • Express + Mongoose 后端代码库——4 小时.

🤯 你当真?Are you serious??

我花了 8 倍的时间在前端?让我们看看原因吧,下面是一个示例,一个很普通的取数据(例如取得所有用户)到前端的流程:

🚧 警告:下面的步骤描述非常技术化,如果你看不太懂没关系。Warning: the following steps are super techy so don’t worry if you get lost.

  1. 创建一个组件来显示用户列表(这一步没啥问题);
  2. 创建一个 fetch 请求到后端接口;
  3. state 中添加一个新字段;
  4. 添加一个 action 用来更新 state 的数据;
  5. 添加一个 thunk 方法来运行 fetch 请求,然后使用新的 action 来更新 state 状态;
  6. 使用 connect() 将这个 thunk 方法加到组件中的 dispatch 方法中;
  7. 再次使用 connect()state 中提取数据;
  8. 在组件的 prop types 属性类型中声明 thunk 方法和提取的数据字段;
  9. componentDidMount() 方法中调用 thunk 方法;
  10. 最后,渲染数据到界面;

我的天……10步,回到 Ruby on Rails 的时代,我只需要把数据放到 HTML 的模板中就完事儿了,达到的效果差不多,我想这中间肯定有什么问题吧?!

☝️ 一条新的路径 A New Approach

Redux 只是解决了前端数据的一致性,但它也带来了如前所述的问题,那么它的价值到底是什么?

基本上我们重写了整个前端只是解决了屈指可数的几个小问题。

Facebook 也意识到了这个问题,启动了一个新项目叫 GraphQL,GraphQL 目前还是个技术名词,我不确定大家是否知道它为什么酷?

GraphQL 完全不同于 Redux,Facebook 又创造了一个大神级的产品,但却没指出这宝贝为什么这么重要,这也是为什么我花时间写此文的原因。

简言之,如果说 Redux 是一匹马的话,GraphQL 就是一辆车。

什么?怎么 Redux 成了一匹马?

我之所以把它们比做一匹马和一辆车,原因是这俩完全是两个物种,一个是有四条腿的马动物,一个是有四个轮子的机器。然而,它们的作用是一样的,都是把人运到想去的地方。虽然它们各自有不同的适合场景,但通常来说,汽车会更快些。

那么,GraphQL 到底是什么?

官方文档是这样说的:“GraphQL 是一种 APIs 接口的查询语言”,感觉不清不楚的,其实他们所谓的查询语言基本上一个就可以替代上百个 HTTP 接口,因为这个技术还很新,所以文档和支持的技术还有点难懂,有一定的学习曲线。这儿给你一个例子看是否有帮助:

GraphQL 可以替代类似这样的接口:

  • GET /users/1234567890
  • POST /cars
  • PUT /example/endpoints

只查询你需要的字段,如下:

{
  user(id: "1234567890") {
    name,
    email
  }
}

返回:

{
  "user": {
    "name": "Luke Skywalker",
    "email": "luke@iamyourfather.com"
  }
}

等一下——自定义的查询……这可是需要点儿时间去实现的,也许你这么认为~

但实际上不用,原因在于:由于只请求需要的数据,突然你不需要那么多服务端请求了,也就是说你不需要写那么多代码去处理那么多服务端请求了,于是,你就节省了大量不需要实现的代码和时间。

🤷‍ 但这就能替代 Redux 了吗?But how does this replace Redux?

问得好!简单地说,不能。不过,它鼓励你不要象 Redux 那样把所有信息存在一个单独的对象中,因为每个查询只针对应用的一小部分,而不是整个应用。在一整个应用的数据源中只关注一小部分,这应该算是个 anti-pattern 反模式、反常识(甚至是有点不合逻辑)的。

通过使用 GraphQL 你就可以摆脱对 Redux 的依赖从而省掉大量的代码。

还有一点要注意:Redux 和 GraphQL 是可以共存的,这样你可以平滑地过渡,这儿有一些关于两者整合的文章:

Integrating with Redux | Apollo React Docs

用不用 Redux 变成一种选择。是用它解决一些小任务而面对头疼的问题,还是换一种方法完成那些任务?

那么,你会怎么选择?

Redux 在当时确实解决了问题,但就在同时,Web 开发行业又在 Web sockets 领域有了巨大的进步。

Web sockets 是在服务端和客户端建立持续的连接,服务端就可以通知客户端何时更新。你猜怎么着?GraphQL 用一种叫 subscriptions 的订阅技术直接就能支持 web sockets,我们可以用这种 subscriptions 的订阅机制来更新应用中想保持同步的部分。

核心的区别在于:与其让客户端(用 Redux)告诉我们哪里要更新,不如让服务端直接通知客户端更新。结果是一样的,这儿有一些例子是怎么用 MongoDB 或 Mongoose 实现 Web socket 和 subscriptions 的。

A Node.js Perspective on MongoDB 3.6: Change Streams

Mongoose v5.2.12: API — Model.watch()

🚀 未来很精彩!The Future Looks Awesome!

GraphQL 开发没多久,但眼下也可以用在产品上了。我不想撒谎,官方文档确实能把人搞晕,需要对 JavaScript 和 服务端运行机制有很强的理解才行。然而如果你还没那么强,但想了解更多,这有一个很流行的教程:

GraphQL: A query language for APIs.

还有很多有用的库可以帮你逐步地整合 GraphQL 到已有产品中。不用担心,你不用一次弄完,这些库可以帮你轻松地、慢慢地改善你的应用。Apollo 就是一家做这事儿的公司。

Apollo GraphQL

好了,我希望这篇文章可以对阐明一些复杂的概念有帮助。

如果你喜欢这篇文章,请点赞——这对我来说是很大的鼓励——或者有问题请留言。

谢谢!🙌