補了一些關於 Respo Effects 的文檔, 英文細節有點吃力,
https://github.com/Respo/respo/wiki/defeffect
關於 Respo 的設計思路和功能取捨, 這邊能夠再描述詳細一些.git
比方說有個組件要增長反作用,github
(defcomp comp-a [x y z] (div {}))
此次更新之後, respo.core
當中新增了一個 defeffect
的宏用來定義反作用,defeffect
須要的不僅僅是多個參數, 並且是不少組參數.數組
(defeffect effect-a [x y] [action el *local] (println "effects"))
[x y]
固然就是參數了. 框架渲染過程中會自動插入參數的值,
另外框架會插入 action
表示 :mount
:update
:unmount
,
以及 el
是組件根節點, 也是由框架獲取.框架
這個宏的實現, 就是把代碼轉換成一個函數, 函數返回的是個 HashMap,函數
(defmacro defeffect [effect-name args params & body] `(defn ~effect-name [~@args] (merge respo.schema/effect {:name ~(keyword effect-name) :args [~@args] :coord [] :method (fn [[~@args] [~@params]] ~@body)})))
上面定義獲得的 effect-a
就是一個函數, 能夠經過 (effect-a x y)
調用,
在組件當中使用的時候, 就是把返回值變成數組, 在數組當中加上反作用spa
(defcomp comp-a [x y z] [ (effect-a x y) (div {}) ])
後面就依靠 Respo 的渲染代碼, 內部進行判斷, 對 effect 進行處理.設計
因爲 effect 沒有直接區分開不一樣的生命週期, action
使用時須要自行判斷,code
(case action :mount (do) :update (do) :unmount (do) (do))
*local
的存在, 是爲了應付可能存在的存儲局部狀態的需求.
好比在 mount 的時候建立的數據, 若是在 update 和 unmount 須要用到,
目前的設計當中, 就須要組件提供私有的狀態用於傳遞.
須要注意, 這個 *local
實際上對應的 React 當中的 ref,
也就是說, 在 *local
上修改數據, 不會出發 rendering 的行爲.component
React 當中組件定義的方式比較簡單,生命週期
(defcomp comp-a [x y] (div {} (div {} (<> "DEMO"))))
而後會通過一次宏展開, 宏的實現是
(defmacro defcomp [comp-name params & body] `(defn ~comp-name [~@params] (merge respo.schema/component {:args (list ~@params) , :name ~(keyword comp-name), :render (fn [~@params] (defn ~(symbol (str "call-" comp-name)) [~'%cursor] ~@body))})))
上面的組件通過 (comp-a x y)
這樣的調用以後, 會獲得一個 HashMap,
{:name :comp-a :args '(x y) :render (fn [x y] (defn call-comp-a [%cursor] (div {} (div {} (<> "DEMO")))))}
能夠看到其中沒有實現生命週期的信息.
這個高階函數在運行時會繼續被處理, 添加所需的參數, 再被計算.
這個結構當中並無預留跟 React 類似的組件生命週期,
並且也不適合用方法進行擴展, 因此比較難直接有 React class 組件那種寫法.
若是須要在組件當中支持反作用的, 至少要在組件的表上加上 effects 的位置,
{:name :comp-a :args '() :render (fn []) ; add :effects [(fn [])]}
原先的 defeffect
的 API 寫出來, 我大體肯定了須要哪些參數,
好比 [a b]
參數, 界面渲染和更新當中使用,
而後是 action
用來判斷生命週期, el
對應 React 當中的 DOM Ref 用.
有了 defeffect
以後我在考慮, 都是把 effect 插入在 DOM 樹當中,
相似 (div {} (effect-a x y) (div {}))
這樣,
但具體看了實現, 涉及到 DOM Diff 的實現有不少坑, 也就做罷了.
因而想怎樣才能以兼容已有的寫法的方式吧反作用插入進去.. 最簡單就是數組了.
用數組的話, 能夠插入多個 effect, 而且後續也有些許繼續擴展的能力.
這套寫法跟 React Hooks 比起來, 有很多的功能缺失.
特別是 Respo 當中, 基本沒有運行渲染過程再 dispatch actions 的可能.
React 當中頻繁有 componentDidMount 或者 useEffect, 在任什麼時候候修改組件狀態,
並且也沒有限制在這種生命週期時 dispatch actions.
Respo 裏不承認這樣的作法, 這樣會持續衍生出 actions 來.
特別是在 Time Traveling 的場景當中, 這種 actions 就是破壞性的,
一旦切換到舊的某個 action 致使新的 actions 被觸發, 狀態就未必一致了.
總體考慮爲了熱替換方便, 組件局部狀態的變化, 是不鼓勵的.
目前 Respo Effects 算是出如今早期狀態, 後面也可能再調整.
無論怎樣, 此前 Respo 爲了實現純的渲染, 沒有作 effects,
致使跟 JavaScript 生態已有的一些用法不能輕鬆銜接.
如今加上了 Effects, 那些東西終於能夠進行嘗試了.
Respo 最第一版本是 2016 年初開始的, 年中基本完成,這麼多年了, 用的人少, 這方面的需求也沒有太大的問題, 由於場景也有限.我我的以爲 Effects 不會有太多的須要. 仍是以小範圍擴展功能位置.