The Redux Journey 翻譯及分析(上)
Dan Abramov 在 ReactEurope 2016 《The Redux Journey 》,分享了 Redux 的核心思路、一些擴展方法及實踐方式,其維護過程中的設計思路及他從中所學到的東西。
這些思路不僅對 Redux 或 類庫設計與維護有幫助,我想只要涉及到 ecosystem 或是架構設計,都是非常有借鑒意義的。
強烈推薦當前正在使用redux 的開發者們觀看其分享video。 原 slide 及 video 可在這裡找到:https://github.com/gaearon/the-redux-journey
增長的社區
至2016/06, Redux 在 npm 上累計已經下載超過 3百萬 次(2016 June 又再次添加 78萬次),增長非常迅猛;
而最新的 twitter mobile site 也使用了 redux 進行構建,更是這個社區的一劑強心劑。
約束和約定
一般情況下,一個開源庫開發者會更關注其 APIs 與特性(Features), 但其實這只是曝光在表面的內容,redux 在維護時還關注約束與約定 (Constraints and Contracts), 並且給予同樣重要的地位,就像音樂不只關注音符,還關注音符之間的距離,才能編織出優雅的律動(rythem)。
約束:
- 單一狀態樹
- Actions 描述更新
- Reducer 應用更新
所以,在傳統 model 層司空見慣的 setter 在這裡就被禁止了。這就是其體現出來的最核心的約束。
P.S. Redux 中提供出來的 API 非常之少,這就意味著很多傳統的 model 的方式(想做嘛都行)在此都是沒法直接做到的:比如更新過程時訪問其它的狀態,等等。
Debug 流程
因為這些約束,使得 redux 的狀態有了可預測可 log 的能力,這使得在 redux 架構之下原本的很多狀態錯誤能得到更好地跟蹤與調試,步驟如下:
- 給 actions 和 states 打 log: 通常引入 redux-devtools 就自動完成了這步操作
- 找到產生問題的壞 state
- 查看其相關的 action,看看是不是 action 的問題
- 如果 action 沒錯,那就檢查 action 相應的 reducers 是否有問題
- 解決問題,編寫一個單元測試。 這裡就體現出了 redux 的優勢:reducer 和 action 分別是純函數與純對象,針對這兩個東西編寫測試就好,頂多針對相應的 action creator 再編寫一個測試。
一切都是數據
感謝單一狀態樹,狀態變得非常易於維護:因為他就是一個純對象,並且可以序列化:
- 易於持久化:只需要 JSON.stringify 保存起來即可
- 能有通用的基於 state 的 render 邏輯,使得 UI 狀態可預測
- 能記錄用戶所有的操作與狀態: 反正 Action 和 state 都是純對象
- 易於 rollback 或 undo:只需要回溯一次 actions 就好了
- 易於協同合作: 所有合作者只管提交 action 即可,同步也同步 action queue 就好了, 而且這些都是純對象!
約束與功能
在設定一些約束的時候,就會出現有些之前無約束時能做的事情在這裡被禁止了。所以,通常需要引入新的功能或是在原有功能基礎上,提供方式解決同樣的問題。
約定 Contracts
Redux 的基礎的約定包括了: Reducers, Selectors, Middlewares, Enhancers 。但其實並不是所有人都得用到所有的約定,很可能只需要用到其中幾個即可。
- Reducer: (state, action) => state Reducer 是純函數,所以很方便其進行組合,比如 redux 提供出來的 combineReducers ,又比如直接在一個 reducer 里調用另一個 reducer。 再次強調, reducer 是純函數,因此可以隨意發揮,只要保持純函數即可。
- selector: (state, ...args) => derivation selector 其實並不是 redux 的核心部分,但在實踐中顯得十分有用,比如需要對某些 UI 使用到的 state 進行緩存,比如提取一部分 state 並做相應處理以適配 UI 的需求等等。 此外, selector 大可以作為 reducer 的一部分存在 ,這樣的話 select 行為及其結果就也可以作為 action 與 state 進行統一地跟蹤。
- 高階 reducer (Higher Order Reducers): (reducer, ...args) => reducer reducer 是純函數,所以大可以盡情發揮函數式的優勢,即可以將 reducer 通過一些參數進行包裝,這樣一些通用的特性就可以注入到原本的 reducer 中。 典型的應用為: undoable reducer (將原本的 state 轉化為{ past: [...states], present: state } ), redux-optimistic-ui, react-redux-form 等。
- Middlewares: 提供一個方式來對所有的 action 進行逐一處理 常用於增強處理非同步 action creator 的功能。 典型應用如: redux-logger, redux-observable, apollo-client (client for GraphQL) 等
- Enhancers: createStore => createStore 介入到 store 產生的過程,以對 store 做一些增強。 典型應用為 redux-batch-subscribe, redux-loop, redux-devtools-extension 等
Contracts 與 API
協議需要像 API 一樣非常小心地設計,這影響到了他人如何與這個架構協作。
對於 library 的 ecosystem 來說非常重要。
小結
這次分享的內容非常豐富,留一部分內容在下篇介紹,地址:https://zhuanlan.zhihu.com/p/21488389
後面的主要內容有:
- Lessons Learned: 作者在維護 redux 一年期間所學到的東西
- Future of redux: 未來的 redux 會是怎樣的
- One More Thing
- QA: 其中探討到 redux 的來源及核心觀點的產生等
推薦閱讀:
※React異常處理
※Learn CSS Animations: From A Designer's Perspective
※#研發解決方案#共享能力的數屏
※創建 React 動畫的五種方式
※web 開發中無處不在的狀態機