目前的 ClojureScript React 綁定都是比較複雜的, 好比 Reagent, 作了很多的修改,
我打算看看直接用 cljs 裸寫, 按照 React 自己的語義, 會是什麼樣子,
網上搜到幾個版本的代碼, 總之核心代碼就是這樣了git
(defn my-component [props context updater] (cljs.core/this-as this (js/React.Component.call this props context updater) ;; anything else you want to set-up. use goog.object/set on this this)) (gobj/extend (.. my-component -prototype) js/React.Component.prototype)
https://gist.github.com/peste...
https://gist.github.com/peste...
https://gist.github.com/thhel...github
最關鍵的部分就是定義一個子類繼承 React.Component , 而後增長 render 方法, 參考:
https://developer.mozilla.org...this
// Rectangle - subclass function Rectangle() { Shape.call(this); // call super constructor. } // subclass extends superclass Rectangle.prototype = Object.create(Shape.prototype); Rectangle.prototype.constructor = Rectangle;
最終獲得的一個版本是這樣,prototype
(def comp-input-area (let [Child (fn [props context updater] (this-as this (.call React/Component this props context updater) (set! (.-state this) (clj->js {:draft "initial thing"})) this))] (set! (.-prototype Child) (.create js/Object (.-prototype React/Component))) (set! (.. Child -prototype -constructor) React/Component) (set! (.. Child -prototype -render) (fn [] (this-as this (div {} (input {:value (^js .-draft (^js .-state this)), :onChange (fn [event] (.setState this (clj->js {:draft (.. event -target -value)})))}) (^js .-draft (^js .-state this)))))) Child))
注意用 this-as
這個 macro 來聲明 this, 這個在 cljs 是不能隨便用的,
https://stackoverflow.com/a/2...
不過這個 macro 有坑, 我用 let
的時候, this
被綁定到 window
上去了,
cljs 編譯生成的代碼存在一些問題, 感受 this
怎麼說其實仍是很成問題的code
完整代碼涉及到更多的 InterOp 用法, 不專門寫了.
大概的意思就是須要轉不少類型, 在上面的例子當中也看到了.
這樣一來, 經過 macro 之類的手段在語法上作改進, 很難了.component
另外看到 JavaScript 有個 reify https://github.com/clojure/cl...
按說能夠簡化語法, 並且在 Om 代碼有到看相似的用法, 無論比較複雜.
直接跟上面的例子對比, 初始化 state 的地方很差寫.繼承
總之很差徹底按照 React 的語義直接封裝了.
當日內 Hooks 出來有帶來一些改變, 不是很肯定能搞成什麼樣, 社區也在探索中.
https://github.com/Lokeh/hook...ip