目前的 ClojureScript React 绑定都是比较复杂的, 比如 Reagent, 做了不少的修改,
我打算看看直接用 cljs 裸写, 按照 React 本身的语义, 会是什么样子,
网上搜到几个版本的代码, 总之核心代码就是这样了
(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...
最关键的部分就是定义一个子类继承 React.Component , 然后增加 render 方法, 参考:
https://developer.mozilla.org...
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
最终得到的一个版本是这样,
(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
怎么说其实还是很成问题的
完整代码涉及到更多的 InterOp 用法, 不专门写了.
大概的意思就是需要转很多类型, 在上面的例子当中也看到了.
这样一来, 通过 macro 之类的手段在语法上做改进, 很难了.
另外看到 JavaScript 有个 reify https://github.com/clojure/cl...
按说可以简化语法, 而且在 Om 代码有到看类似的用法, 不管比较复杂.
直接跟上面的例子对比, 初始化 state 的地方不好写.
总之不好完全按照 React 的语义直接封装了.
当日内 Hooks 出来有带来一些改变, 不是很确定能搞成什么样, 社区也在探索中.
https://github.com/Lokeh/hook...