作者:Jack Scott
原文 國內(nèi)網(wǎng)可能訪問不到……大致翻譯如下:
本文主要分析了一下我們過去為什么需要 Redux吱晒,而為什么以后又不再需要了财著。
在過去的幾年里联四,互聯(lián)網(wǎng)技術(shù)已經(jīng)轉(zhuǎn)向用前端 JavaScript 框架來實現(xiàn)網(wǎng)站和手機應用,以達到更好的用戶體驗撑教。這非常棒 ?? 朝墩,我個人很欣賞這些框架提供的靈活性。
但是靈活得是否有些過頭了……
為了能更好地理解這個問題伟姐,讓我們把時鐘撥回到 JavaScript 框架出現(xiàn)以前收苏,看看我們是怎么開發(fā)應用的亿卤。
? JavaScript 以前的大陸 A Land Before JavaScript…
在前幾個前端框架(最值得注意的是AngularJS、Backbone和Ember)出現(xiàn)之前鹿霸,我們只是在服務(wù)器上渲染模板怠噪,然后將完整的HTML頁面發(fā)送到瀏覽器。當時流行的框架包括:
- 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)頁效果
在這些框架上編寫的應用有一些問題淑趾,但總得來說還不錯,直到有一天 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ā)展起來:
- 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 年前
這就開始了應用開發(fā)模式的重大轉(zhuǎn)變沥匈。之前由服務(wù)端直接處理的 MVC 模式被分拆為兩部分:一個服務(wù)端的 MC 和一個客戶端的 V(MC),客戶端使用的就是上述的前端框架忘渔。在早期的這些框架中高帖,還包含 Model 和 Controller 層在 View 中。兩份 Model 和 Controller畦粮,前端也有一份 MC散址,這樣看來是要寫更多的代碼了。
??? 臉書有個頭疼的問題 Facebook Had A Problem
正當所有人開心地使用上述方案的時候宣赔,F(xiàn)acebook 來了爪飘,隨著它的迅速崛起,F(xiàn)acebook 變成了最大的網(wǎng)頁應用拉背,而為了解決頁頭上即時消息的數(shù)量顯示問題(實際上這個小問題在海量用戶使用的場景下是比較復雜的)师崎,舊的方案也并不能很好地應對……
于是他們推出了 React:
- React(前端)?——2013年?三月發(fā)布 ~5 年前
而 React 只管 View 層,于是又有了 Flux椅棺,之后是 Redux(Redo Flux)犁罩,有興趣了解詳情的可以看這個視頻:
?? ……于是這東西變得象個鴨梨 …Then Things Started to Go Pear Shaped
Redux 的工作方式是把一個應用中幾乎所有的動態(tài)信息都保存在一個 JavaScript 對象中齐蔽。這樣不管你在應用的哪個地方看到的數(shù)據(jù)都來自同一個地方,也就能保持一致床估,這樣也就解決了 Facebook 所頭疼的問題含滴。
于是突然又來了一種新框架:React + Redux 解決方案,F(xiàn)acebook 用它來解決問題丐巫,而從此以后所有人都過上了幸福的生活……對嗎谈况?
? 不盡然 Not quite.
問題在于人們(包括我)開始用一個對象保存所有信息,其中的每一部分都是由服務(wù)端獲得递胧,沒錯這可以保證數(shù)據(jù)的及時更新碑韵,但同時也存在 3 個缺點:
- 這需要大量的多余的代碼才能很好地運行,這很浪費時間缎脾。
- 因為所有代碼放在一處祝闻,這可能帶來“舊數(shù)據(jù)”的問題,也就是說你可能在應用中見到一些來自之前狀態(tài)的不想要的數(shù)據(jù)遗菠。
- 對于新的開發(fā)人員學習曲線太高联喘,繼而使得前端Web開發(fā)很難被新的開發(fā)人員采用。
我們有一個向用戶顯示數(shù)據(jù)的相對簡單的老式 MVC 框架應用辙纬,其中也就是幾個簡單的模板豁遭,在2005年,我們成功地將它轉(zhuǎn)換為一個單頁面應用贺拣,它的前端代碼通常是后端代碼的 10 倍堤框。例如:我最近開發(fā)了一個簡單的應用,然后我用 WakaTime 來衡量我在編碼上的耗時情況纵柿,以下是測量結(jié)果:
- React Redux 前端代碼庫—— 32 小時.
- Express + Mongoose 后端代碼庫——4 小時.
?? 你當真蜈抓?Are you serious??
我花了 8 倍的時間在前端?讓我們看看原因吧昂儒,下面是一個示例沟使,一個很普通的取數(shù)據(jù)(例如取得所有用戶)到前端的流程:
?? 警告:下面的步驟描述非常技術(shù)化,如果你看不太懂沒關(guān)系渊跋。Warning: the following steps are super techy so don't worry if you get lost.
- 創(chuàng)建一個組件來顯示用戶列表(這一步?jīng)]啥問題)腊嗡;
- 創(chuàng)建一個
fetch
請求到后端接口; - 在
state
中添加一個新字段拾酝; - 添加一個
action
用來更新state
的數(shù)據(jù)燕少; - 添加一個
thunk
方法來運行fetch
請求,然后使用新的action
來更新state
狀態(tài)蒿囤; - 使用
connect()
將這個thunk
方法加到組件中的dispatch
方法中客们; - 再次使用
connect()
從state
中提取數(shù)據(jù); - 在組件的
prop types
屬性類型中聲明thunk
方法和提取的數(shù)據(jù)字段; - 在
componentDidMount()
方法中調(diào)用thunk
方法底挫; - 最后恒傻,渲染數(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ù)還有點難懂厦幅,有一定的學習曲線沾鳄。這兒給你一個例子看是否有幫助:
GraphQL 可以替代類似這樣的接口:
- GET /users/1234567890
- POST /cars
- PUT /example/endpoints
只查詢你需要的字段,如下:
{
user(id: "1234567890") {
name,
email
}
}
返回:
{
"user": {
"name": "Luke Skywalker",
"email": "luke@iamyourfather.com"
}
}
等一下——自定義的查詢……這可是需要點兒時間去實現(xiàn)的确憨,也許你這么認為~
但實際上不用译荞,原因在于:由于只請求需要的數(shù)據(jù),突然你不需要那么多服務(wù)端請求了休弃,也就是說你不需要寫那么多代碼去處理那么多服務(wù)端請求了吞歼,于是,你就節(jié)省了大量不需要實現(xiàn)的代碼和時間塔猾。
??? 但這就能替代 Redux 了嗎篙骡?But how does this replace Redux?
問得好!簡單地說丈甸,不能糯俗。不過,它鼓勵你不要象 Redux 那樣把所有信息存在一個單獨的對象中睦擂,因為每個查詢只針對應用的一小部分得湘,而不是整個應用。在一整個應用的數(shù)據(jù)源中只關(guān)注一小部分顿仇,這應該算是個 anti-pattern
反模式淘正、反常識(甚至是有點不合邏輯)的。
通過使用 GraphQL 你就可以擺脫對 Redux 的依賴從而省掉大量的代碼臼闻。
還有一點要注意:Redux 和 GraphQL 是可以共存的鸿吆,這樣你可以平滑地過渡,這兒有一些關(guān)于兩者整合的文章:
Integrating with Redux | Apollo React Docs
用不用 Redux 變成一種選擇述呐。是用它解決一些小任務(wù)而面對頭疼的問題伞剑,還是換一種方法完成那些任務(wù)?
那么市埋,你會怎么選擇黎泣?
Redux 在當時確實解決了問題,但就在同時缤谎,Web 開發(fā)行業(yè)又在 Web sockets
領(lǐng)域有了巨大的進步抒倚。
Web sockets 是在服務(wù)端和客戶端建立持續(xù)的連接,服務(wù)端就可以通知客戶端何時更新坷澡。你猜怎么著托呕?GraphQL 用一種叫 subscriptions
的訂閱技術(shù)直接就能支持 web sockets,我們可以用這種 subscriptions
的訂閱機制來更新應用中想保持同步的部分。
核心的區(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)品中盅弛。不用擔心钱骂,你不用一次弄完,這些庫可以幫你輕松地挪鹏、慢慢地改善你的應用见秽。Apollo 就是一家做這事兒的公司。
好了狰住,我希望這篇文章可以對闡明一些復雜的概念有幫助张吉。
如果你喜歡這篇文章齿梁,請點贊——這對我來說是很大的鼓勵——或者有問題請留言催植。
謝謝!??