如何看待基於 Atom 和 Lens 的狀態管理工具 Calmm-js 和 Focal?
最近發現了兩個狀態管理的庫:
Calmm-js: calmm-js/documentation
Focal: grammarly/focal
以及一個 Cycle.js 的變體 TSERS: tsers-js/core
都採用的是通過 FRP 實現的基於 Atom 和 Lens 的狀態管理,採取的是和 Redux、Mobx 不同的思路。
在全局會有一個巨型 Atom 保存整個狀態,再通過 Lens 得到子狀態,傳遞給子組件,子組件對這個子狀態進行變更,從而影響整個 Atom。
比較有意思的一點是子狀態和頂層的 Atom 是完全分形的,組件根本無需關心傳入的狀態在狀態樹里的位置,根也好,葉子也好,一視同仁。
作者也闡述了為何要這樣設計,感覺挺有啟發性的:What is my state?
對於細節沒理解透, 但是在 ClojureScript 這邊有相關的研究, 包括 JavaScript 社區早期的一些 cursor library 也是參考 ClojureScript 當中的 Cursor 設計的. 大致上 Lens 是在 Haskell 之類的語言當中對於不可變數據的嵌套的結構設計的添加和修改的操作, 通過定義一個觀察的位置, 從而設計一個快速查看和修改數據結構的方案. 而 Cursor 就是 ClojureScript 作者基於 Lens 設計出來的, 由於 Clojure 當中區分了不可變數據和可變狀態, 方案被簡化了, 大致上就是 Focal 當中的 Atom, 可以被查看/修改/監聽, 以及可以基於路徑創建 sub-cursor 對樹形的數據進行選擇.
奇怪的是 Cursor 是在 Om 當中提出的, 到了 Om 2 作者參考 GraphQL 提出了 Queries 這個方案, 反而 Cursor 不被推薦了, 我還不理解. 以我目前的理解, 這個方案目標還是為了擁抱不可變數據以及全局狀態, 而 Lens 跟 Cursor 都是挺有效率的方案, 我自己的代碼當中也從 Cursor 得到了不少的借鑒, 但未必是完美的方案, Flux 當中有 Actions 的抽象, 方便做 time travelling, 在 Cursor 中成了看上去直接拿到引用進行修改了, 挺取巧的, 反而喪失了 time travelling 的可能.
另外, 這個方案不好說是 FRP, 甚至 Rx 屬於 FRP, 因為 FRP 本身概念比較有爭議, Elm 是基於 FRP 設計的, 但是的 ClojureScript 這邊的方案很少說基於 FRP, 而 Rx 方案就更加偏離了.
相關資料:
https://twitter.com/swannodette/status/420753608968536064 https://github.com/omcljs/om/wiki/Cursors https://github.com/omcljs/om/wiki/Queries-With-Unions https://github.com/tonsky/rum/blob/gh-pages/src/rum/cursor.cljs https://clojuredocs.org/clojure.core/atomdustingetz/react-cursorYomguithereal/baobab學了一招奇技淫巧……一直在因為immutable要拼字元串路徑沒有補全和提示發愁,看了focal才知道還能這麼玩.......
推薦閱讀:
TAG:前端框架 | React | FunctionalReactiveProgramming | Cyclejs |