关于 ClojureScript 裸写 stateful React Component

36次阅读

共计 1665 个字符,预计需要花费 5 分钟才能阅读完成。

目前的 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…

正文完
 0