Prior Art: Influences on the design of Redux">Prior Art: Influences on the design of Redux">
跳至主要內容

先前技術

Redux 具有混合的傳統。它類似於一些模式和技術,但在重要方面也有所不同。我們將在下面探討一些相似點和不同點。

開發人員體驗

Dan Abramov(Redux 的作者)在準備他的 React Europe 演講時撰寫了 Redux,演講標題為 “熱重載與時光旅行”。他的目標是建立一個具有最小 API 但行為完全可預測的狀態管理程式庫。Redux 可以實現記錄、熱重載、時光旅行、通用應用程式、記錄和重播,而不需要開發人員的任何參與。

Dan 在 Changelog 第 187 集 中談到了他的部分意圖和方法。

影響

Redux 發展了 Flux 的想法,但透過參考 Elm 的提示來避免其複雜性。即使您沒有使用過 Flux 或 Elm,Redux 也只需要幾分鐘就可以開始使用。

Flux

Redux 的靈感來自 Flux 的幾個重要特質。與 Flux 類似,Redux 規定你應將模型更新邏輯集中在應用程式的特定層級(Flux 中的「儲存體」,Redux 中的「簡化器」)。兩者都告訴你,不要讓應用程式程式碼直接變異資料,而是應將每個變異描述為一個稱為「動作」的純粹物件。

與 Flux 不同,Redux 沒有 Dispatcher 的概念。這是因為它依賴純粹函式,而非事件發射器,而且純粹函式容易組合,不需要額外的實體管理它們。根據你如何看待 Flux,你可能會將這視為一種偏差或實作細節。Flux 通常被 描述為 (state, action) => state。從這個意義上來說,Redux 忠於 Flux 架構,但由於純粹函式的關係,使得它更為簡潔。

與 Flux 的另一個重要差異是,Redux 假設你絕不會變異資料。你可以為你的狀態使用純粹物件和陣列,但強烈建議不要在簡化器內變異它們。你應該總是回傳一個新的物件,可以使用物件擴散運算子或 Immer 不可變更新函式庫 來執行此操作。

雖然在技術上有可能 撰寫不純粹的簡化器,以變異資料以應付效能的臨界情況,但我們強烈建議你不要這麼做。時間旅行、記錄/重播或熱載入等開發功能將會中斷。此外,在多數實際應用程式中,不可變性似乎不會造成效能問題,因為正如 Om 所示,即使你損失了物件配置,但由於簡化器純粹,你可以確切知道哪些部分已變更,因此仍能透過避免昂貴的重新渲染和重新計算而獲益。

值得一提的是,Flux 的創作者 認可 Redux

Elm

Elm 是一種由 Evan Czaplicki 所建立,並受到 Haskell 啟發的函式式程式語言。它強制執行 「模型檢視更新」架構,其中更新具有下列簽章:(action, state) => state。Elm 的「更新器」與 Redux 中的簡化器具有相同目的。

與 Redux 不同,Elm 是一種語言,因此它能夠受益於許多功能,例如強制純粹性、靜態類型、開箱即用的不可變性以及模式比對(使用 case 表達式)。即使你沒有計畫使用 Elm,你也應該閱讀 Elm 架構並試用看看。有一個有趣的 JavaScript 函式庫遊樂場實作類似的概念。我們應從中尋找 Redux 的靈感!我們可以透過 使用漸進式類型化解決方案,例如 Flow,更接近 Elm 的靜態類型化。

Immutable

Immutable 是一個實作持久資料結構的 JavaScript 函式庫。效能良好,並具備慣用的 JavaScript API。

(請注意,儘管 Immutable.js 有助於激發 Redux,但我們現在建議 改用 Immer 來進行不可變更新。)

Redux 不在乎你如何儲存狀態,它可以是純粹物件、Immutable 物件或其他任何東西。你可能需要一個(反)序列化機制來撰寫通用應用程式,並從伺服器中補充其狀態,但除此之外,你可以使用任何資料儲存函式庫只要它支援不可變性。例如,將 Backbone 用於 Redux 狀態沒有意義,因為 Backbone 模型是可變的。

請注意,即使你的不可變函式庫支援游標,也不應該在 Redux 應用程式中使用它們。整個狀態樹應視為唯讀,你應該使用 Redux 來更新狀態,並訂閱更新。因此,透過游標寫入對 Redux 來說沒有意義。如果你使用游標的唯一情況是將狀態樹與 UI 樹分離,並逐步精煉游標,你應該改看選擇器。選擇器是可以組合的 getter 函式。請參閱 reselect 以取得可組合選擇器非常棒且簡潔的實作。

Baobab

Baobab 是另一個廣受歡迎的函式庫,實作了不可變 API 來更新純粹 JavaScript 物件。雖然你可以將它與 Redux 搭配使用,但將它們一起使用的好處很小。

Baobab 提供的大部分功能都與使用游標更新資料有關,但 Redux 強制執行更新資料的唯一方法是發送動作。因此,它們以不同的方式解決相同的問題,並且不會相互補充。

與 Immutable 不同,Baobab 尚未實作任何特殊的有效率資料結構,因此將它與 Redux 搭配使用並不會真正獲得任何好處。在這種情況下,只使用純粹物件會比較容易。

RxJS

RxJS 是一種管理非同步應用程式複雜性的絕佳方法。事實上 有一個專案致力於建立一個將人機互動建模為相互依賴的可觀察物件的函式庫

將 Redux 與 RxJS 一起使用是否有意義?當然!它們可以完美搭配。例如,可以輕鬆地將 Redux 儲存庫公開為可觀察對象

function toObservable(store) {
return {
subscribe({ next }) {
const unsubscribe = store.subscribe(() => next(store.getState()))
next(store.getState())
return { unsubscribe }
}
}
}

同樣地,你可以組合不同的非同步串流,將它們轉換為動作,然後再將它們提供給 store.dispatch()

問題是:如果你已經使用 Rx,是否真的需要 Redux?也許不需要。在 Rx 中重新實作 Redux 並不困難重新實作 Redux。有人說使用 Rx .scan() 方法只要兩行就能完成。這很有可能!

如果你有疑問,請查看 Redux 原始碼(那裡沒有太多內容),以及它的生態系統(例如,開發人員工具)。如果你不太在意它,並且想要一路使用反應式資料流程,你可能想要探索類似 Cycle 的東西,甚至將它與 Redux 結合。讓我們知道進展如何!

見證

「喜歡你使用 Redux 的方式」 Flux 的創建者 Jing Chen

「我在 FB 的內部 JS 討論群組中徵求對 Redux 的意見,它獲得了一致好評。真的很棒。」 Flux 文件的作者 Bill Fisher

「你透過完全不使用 Flux 來發明更好的 Flux,這很酷。」 Cycle 的創建者 André Staltz

感謝

  • Elm 架構,提供一個很好的簡介,說明如何使用簡化器建模狀態更新;
  • 將資料庫翻轉過來,讓我大開眼界;
  • 使用 Figwheel 開發 ClojureScript,讓我相信重新評估應該「正常運作」;
  • Webpack,提供熱模組替換;
  • Flummox,教導我如何不使用樣板或單例來處理 Flux;
  • disto,提供可熱重新載入儲存庫的概念驗證;
  • NuclearJS,證明此架構可以有良好的效能;
  • Om,推廣單一狀態原子的概念;
  • Cycle 用於顯示函式有多常是最佳工具;
  • React 用於務實創新。

特別感謝 Jamie Paton 移交 redux NPM 套件名稱。

贊助者

Redux 的原始工作是由 社群資助。認識讓這項工作成為可能的傑出公司

查看原始 Redux 贊助者的完整清單,以及持續增加的 使用 Redux 的個人和公司清單