再見了 Redux (翻譯)

作者:Jack Scott

原文 國內(nèi)網(wǎng)可能訪問不到……大致翻譯如下:

本文主要分析了一下我們過去為什么需要 Redux,而為什么以后又不再需要了。

Goodbye Redux

在過去的幾年里,互聯(lián)網(wǎng)技術(shù)已經(jīng)轉(zhuǎn)向用前端 JavaScript 框架來實現(xiàn)網(wǎng)站和手機應(yīng)用,以達到更好的用戶體驗。這非常棒 ?? ,我個人很欣賞這些框架提供的靈活性。

但是靈活得是否有些過頭了……

為了能更好地理解這個問題,讓我們把時鐘撥回到 JavaScript 框架出現(xiàn)以前,看看我們是怎么開發(fā)應(yīng)用的。

? JavaScript 以前的大陸 A Land Before JavaScript…

在前幾個前端框架(最值得注意的是AngularJS、Backbone和Ember)出現(xiàn)之前,我們只是在服務(wù)器上渲染模板,然后將完整的HTML頁面發(fā)送到瀏覽器。當(dāng)時流行的框架包括:

sf, django, rails
  • Django (Python)——2005年7月21日發(fā)布 ~13 年前
  • Ruby on Rails?——?2005年12月13日發(fā)布 ~13 年前
  • Symphony (PHP)?——?2005年10月22日發(fā)布 ~13 年前

這些框架主要是圍繞了 MVC 概念也就是 Model-View-Controller 來開發(fā)的,Model 表示數(shù)據(jù)的模型,View 表示怎么顯示這些數(shù)據(jù),而 Controller 則連接這兩部分。

我的意思是說,這其中也有 JavaScript,但我們更多的時候是在說 jQuery 做的滑動條和一些完全沒必要的動態(tài)網(wǎng)頁效果

在這些框架上編寫的應(yīng)用有一些問題,但總得來說還不錯,直到有一天 Ryan Dahl 有了一個很棒的主意,他開發(fā)了第一版的 Node.js,可以讓開發(fā)人員寫服務(wù)端程序,而不止是用 JavaScript 做些愚蠢的動畫。

  • Node.js ——2009年5月27日發(fā)布 ~9 年前

猛然間人們似乎看到了 JavaScript 的無限可能性,用一丁點兒的代碼就能做很多事兒,這充分打開了其他開發(fā)人員的想象力,人們不僅創(chuàng)建更多強大的 Node.js 工具,還開始創(chuàng)建有趣的前端框架,在接下來的幾年里,JavaScript 就象滾雪球一樣高速發(fā)展起來:

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

這就開始了應(yīng)用開發(fā)模式的重大轉(zhuǎn)變。之前由服務(wù)端直接處理的 MVC 模式被分拆為兩部分:一個服務(wù)端的 MC 和一個客戶端的 V(MC),客戶端使用的就是上述的前端框架。在早期的這些框架中,還包含 Model 和 Controller 層在 View 中。兩份 Model 和 Controller,前端也有一份 MC,這樣看來是要寫更多的代碼了。

??? 臉書有個頭疼的問題 Facebook Had A Problem

正當(dāng)所有人開心地使用上述方案的時候,F(xiàn)acebook 來了,隨著它的迅速崛起,F(xiàn)acebook 變成了最大的網(wǎng)頁應(yīng)用,而為了解決頁頭上即時消息的數(shù)量顯示問題(實際上這個小問題在海量用戶使用的場景下是比較復(fù)雜的),舊的方案也并不能很好地應(yīng)對……

Facebook head aches

于是他們推出了 React:

  • React(前端)?——2013年?三月發(fā)布 ~5 年前

而 React 只管 View 層,于是又有了 Flux,之后是 Redux(Redo Flux),有興趣了解詳情的可以看這個視頻:

Youku視頻 QQ視頻

?? ……于是這東西變得象個鴨梨 …Then Things Started to Go Pear Shaped

Redux 的工作方式是把一個應(yīng)用中幾乎所有的動態(tài)信息都保存在一個 JavaScript 對象中。這樣不管你在應(yīng)用的哪個地方看到的數(shù)據(jù)都來自同一個地方,也就能保持一致,這樣也就解決了 Facebook 所頭疼的問題。

于是突然又來了一種新框架:React + Redux 解決方案,F(xiàn)acebook 用它來解決問題,而從此以后所有人都過上了幸福的生活……對嗎?

? 不盡然 Not quite.

問題在于人們(包括我)開始用一個對象保存所有信息,其中的每一部分都是由服務(wù)端獲得,沒錯這可以保證數(shù)據(jù)的及時更新,但同時也存在 3 個缺點:

  1. 這需要大量的多余的代碼才能很好地運行,這很浪費時間。
  2. 因為所有代碼放在一處,這可能帶來“舊數(shù)據(jù)”的問題,也就是說你可能在應(yīng)用中見到一些來自之前狀態(tài)的不想要的數(shù)據(jù)。
  3. 對于新的開發(fā)人員學(xué)習(xí)曲線太高,繼而使得前端Web開發(fā)很難被新的開發(fā)人員采用。

我們有一個向用戶顯示數(shù)據(jù)的相對簡單的老式 MVC 框架應(yīng)用,其中也就是幾個簡單的模板,在2005年,我們成功地將它轉(zhuǎn)換為一個單頁面應(yīng)用,它的前端代碼通常是后端代碼的 10 倍。例如:我最近開發(fā)了一個簡單的應(yīng)用,然后我用 WakaTime 來衡量我在編碼上的耗時情況,以下是測量結(jié)果:

  • React Redux 前端代碼庫—— 32 小時.
  • Express + Mongoose 后端代碼庫——4 小時.

?? 你當(dāng)真?Are you serious??

我花了 8 倍的時間在前端?讓我們看看原因吧,下面是一個示例,一個很普通的取數(shù)據(jù)(例如取得所有用戶)到前端的流程:

?? 警告:下面的步驟描述非常技術(shù)化,如果你看不太懂沒關(guān)系。Warning: the following steps are super techy so don't worry if you get lost.

  1. 創(chuàng)建一個組件來顯示用戶列表(這一步?jīng)]啥問題);
  2. 創(chuàng)建一個 fetch 請求到后端接口;
  3. state 中添加一個新字段;
  4. 添加一個 action 用來更新 state 的數(shù)據(jù);
  5. 添加一個 thunk 方法來運行 fetch 請求,然后使用新的 action 來更新 state 狀態(tài);
  6. 使用 connect() 將這個 thunk 方法加到組件中的 dispatch 方法中;
  7. 再次使用 connect()state 中提取數(shù)據(jù);
  8. 在組件的 prop types 屬性類型中聲明 thunk 方法和提取的數(shù)據(jù)字段;
  9. componentDidMount() 方法中調(diào)用 thunk 方法;
  10. 最后,渲染數(shù)據(jù)到界面;

我的天……10步,回到 Ruby on Rails 的時代,我只需要把數(shù)據(jù)放到 HTML 的模板中就完事兒了,達到的效果差不多,我想這中間肯定有什么問題吧?!

?? 一條新的路徑 A New Approach

Redux 只是解決了前端數(shù)據(jù)的一致性,但它也帶來了如前所述的問題,那么它的價值到底是什么?

基本上我們重寫了整個前端只是解決了屈指可數(shù)的幾個小問題。

Facebook 也意識到了這個問題,啟動了一個新項目叫 GraphQL,GraphQL 目前還是個技術(shù)名詞,我不確定大家是否知道它為什么酷?

GraphQL 完全不同于 Redux,F(xiàn)acebook 又創(chuàng)造了一個大神級的產(chǎn)品,但卻沒指出這寶貝為什么這么重要,這也是為什么我花時間寫此文的原因。

簡言之,如果說 Redux 是一匹馬的話,GraphQL 就是一輛車。

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

我之所以把它們比做一匹馬和一輛車,原因是這倆完全是兩個物種,一個是有四條腿的馬動物,一個是有四個輪子的機器。然而,它們的作用是一樣的,都是把人運到想去的地方。雖然它們各自有不同的適合場景,但通常來說,汽車會更快些。

那么,GraphQL 到底是什么?

官方文檔是這樣說的:“GraphQL 是一種 APIs 接口的查詢語言”,感覺不清不楚的,其實他們所謂的查詢語言基本上一個就可以替代上百個 HTTP 接口,因為這個技術(shù)還很新,所以文檔和支持的技術(shù)還有點難懂,有一定的學(xué)習(xí)曲線。這兒給你一個例子看是否有幫助:

GraphQL 可以替代類似這樣的接口:

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

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

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

返回:

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

等一下——自定義的查詢……這可是需要點兒時間去實現(xiàn)的,也許你這么認(rèn)為~

但實際上不用,原因在于:由于只請求需要的數(shù)據(jù),突然你不需要那么多服務(wù)端請求了,也就是說你不需要寫那么多代碼去處理那么多服務(wù)端請求了,于是,你就節(jié)省了大量不需要實現(xiàn)的代碼和時間。

??? 但這就能替代 Redux 了嗎?But how does this replace Redux?

問得好!簡單地說,不能。不過,它鼓勵你不要象 Redux 那樣把所有信息存在一個單獨的對象中,因為每個查詢只針對應(yīng)用的一小部分,而不是整個應(yīng)用。在一整個應(yīng)用的數(shù)據(jù)源中只關(guān)注一小部分,這應(yīng)該算是個 anti-pattern 反模式、反常識(甚至是有點不合邏輯)的。

通過使用 GraphQL 你就可以擺脫對 Redux 的依賴從而省掉大量的代碼。

還有一點要注意:Redux 和 GraphQL 是可以共存的,這樣你可以平滑地過渡,這兒有一些關(guān)于兩者整合的文章:

Integrating with Redux | Apollo React Docs

用不用 Redux 變成一種選擇。是用它解決一些小任務(wù)而面對頭疼的問題,還是換一種方法完成那些任務(wù)?

那么,你會怎么選擇?

Redux 在當(dāng)時確實解決了問題,但就在同時,Web 開發(fā)行業(yè)又在 Web sockets 領(lǐng)域有了巨大的進步。

Web sockets 是在服務(wù)端和客戶端建立持續(xù)的連接,服務(wù)端就可以通知客戶端何時更新。你猜怎么著?GraphQL 用一種叫 subscriptions 的訂閱技術(shù)直接就能支持 web sockets,我們可以用這種 subscriptions 的訂閱機制來更新應(yīng)用中想保持同步的部分。

核心的區(qū)別在于:與其讓客戶端(用 Redux)告訴我們哪里要更新,不如讓服務(wù)端直接通知客戶端更新。結(jié)果是一樣的,這兒有一些例子是怎么用 MongoDB 或 Mongoose 實現(xiàn) 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 開發(fā)沒多久,但眼下也可以用在產(chǎn)品上了。我不想撒謊,官方文檔確實能把人搞暈,需要對 JavaScript 和 服務(wù)端運行機制有很強的理解才行。然而如果你還沒那么強,但想了解更多,這有一個很流行的教程:

GraphQL: A query language for APIs.

還有很多有用的庫可以幫你逐步地整合 GraphQL 到已有產(chǎn)品中。不用擔(dān)心,你不用一次弄完,這些庫可以幫你輕松地、慢慢地改善你的應(yīng)用。Apollo 就是一家做這事兒的公司。

Apollo GraphQL

好了,我希望這篇文章可以對闡明一些復(fù)雜的概念有幫助。

如果你喜歡這篇文章,請點贊——這對我來說是很大的鼓勵——或者有問題請留言。

謝謝!??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容