Allow output from create-class to be used directly by React

This commit is contained in:
Dan Holmsand 2015-10-06 12:49:47 +02:00
parent 4601b37ec5
commit 533c05aaca
4 changed files with 57 additions and 60 deletions

View File

@ -3,7 +3,7 @@
[reagent.impl.batching :as batch]
[reagent.ratom :as ratom]
[reagent.interop :refer-macros [.' .!]]
[reagent.debug :refer-macros [dbg prn dev? warn]]))
[reagent.debug :refer-macros [dbg prn dev? warn warn-unless]]))
(declare ^:dynamic *current-component*)
@ -12,6 +12,16 @@
;;; Argv access
(defn shallow-obj-to-map [o]
(let [ks (js-keys o)
len (alength ks)]
(persistent!
(loop [m (transient {}) i 0]
(if (< i len)
(let [k (aget ks i)]
(recur (assoc! m (keyword k) (aget o k)) (inc i)))
m)))))
(defn extract-props [v]
(let [p (nth v 1 nil)]
(if (map? p) p)))
@ -22,11 +32,13 @@
(if (> (count v) first-child)
(subvec v first-child))))
(defn props-argv [p]
(.' p :argv))
(defn props-argv [c p]
(if-some [a (.' p :argv)]
a
[c (shallow-obj-to-map p)]))
(defn get-argv [c]
(.' c :props.argv))
(props-argv c (.' c :props)))
(defn get-props [c]
(-> (get-argv c) extract-props))
@ -37,6 +49,12 @@
(defn reagent-component? [c]
(-> (get-argv c) nil? not))
(defn cached-react-class [c]
(.' c :cljsReactClass))
(defn cache-react-class [c constructor]
(.! c :cljsReactClass constructor))
;;; State
@ -137,22 +155,22 @@
;; Don't care about nextstate here, we use forceUpdate
;; when only when state has changed anyway.
(let [old-argv (.' c :props.argv)
new-argv (.' nextprops :argv)]
(if (nil? f)
(or (nil? old-argv)
(nil? new-argv)
(not= old-argv new-argv))
(f c old-argv new-argv))))))
new-argv (.' nextprops :argv)
no-argv (or (nil? old-argv) (nil? new-argv))]
(cond
(nil? f) (or no-argv (not= old-argv new-argv))
no-argv (f c (get-argv c) (props-argv c nextprops))
:else (f c old-argv new-argv))))))
:componentWillUpdate
(fn [nextprops]
(this-as c
(f c (props-argv nextprops))))
(f c (props-argv c nextprops))))
:componentDidUpdate
(fn [oldprops]
(this-as c
(f c (props-argv oldprops))))
(f c (props-argv c oldprops))))
:componentWillMount
(fn []
@ -268,8 +286,7 @@
{:pre [(map? body)]}
(let [spec (cljsify body)
res (.' js/React createClass spec)]
(util/cache-react-class res res)
res))
(cache-react-class res res)))
(defn component-path [c]
(let [elem (some-> (or (some-> c (.' :_reactInternalInstance))
@ -295,23 +312,24 @@
""))
""))
(defn shallow-obj-to-map [o]
(into {} (for [k (js-keys o)]
[(keyword k) (aget o k)])))
(def elem-counter 0)
(defn fn-to-class [f]
(assert (ifn? f) (str "Expected a function, not " (pr-str f)))
(warn-unless (not (and (fn? f)
(some? (.' f :type))))
"Using native React classes directly in Hiccup forms "
"is not supported. Use create-element or "
"adapt-react-class instead: " (.' f :type)
(comp-name))
(let [spec (meta f)
withrender (assoc spec :reagent-render f)
res (create-class withrender)]
(cache-react-class f res)))
(defn as-class [tag]
(if-some [cached-class (cached-react-class tag)]
cached-class
(fn-to-class tag)))
(defn reactify-component [comp]
(.' js/React createClass
#js{:displayName "react-wrapper"
:render
(fn []
(this-as this
(as-element
[comp
(-> (.' this :props)
shallow-obj-to-map
;; ensure re-render, might get mutable js data
(assoc :-elem-count
(set! elem-counter
(inc elem-counter))))])))}))
(as-class comp))

View File

@ -196,26 +196,6 @@
:id id
:className class}))
(defn fn-to-class [f]
(assert (ifn? f) (str "Expected a function, not " (pr-str f)))
(warn-unless (not (and (fn? f)
(some? (.' f :type))))
"Using native React classes directly in Hiccup forms "
"is not supported. Use create-element or "
"adapt-react-class instead: " (.' f :type)
(comp/comp-name))
(let [spec (meta f)
withrender (assoc spec :reagent-render f)
res (comp/create-class withrender)
wrapf (util/cached-react-class res)]
(util/cache-react-class f wrapf)
wrapf))
(defn as-class [tag]
(if-some [cached-class (util/cached-react-class tag)]
cached-class
(fn-to-class tag)))
(defn get-key [x]
(when (map? x)
;; try catch to avoid clojurescript peculiarity with
@ -229,7 +209,7 @@
(-> v (nth 1 nil) get-key)))
(defn reag-element [tag v]
(let [c (as-class tag)
(let [c (comp/as-class tag)
jsprops #js{:argv v}]
(some->> v key-from-vec (.! jsprops :key))
(.' js/React createElement c jsprops)))

View File

@ -8,12 +8,6 @@
;;; Props accessors
(defn cached-react-class [c]
(.' c :cljsReactClass))
(defn cache-react-class [c constructor]
(.! c :cljsReactClass constructor))
;; Misc utilities
(defn memoize-1 [f]

View File

@ -487,11 +487,14 @@
(deftest test-reactize-component
(let [ae r/as-element
ce r/create-element
c1r (fn [p]
a (atom nil)
c1r (fn [p & args]
(reset! a args)
[:p "p:" (:a p) (:children p)])
c1 (r/reactify-component c1r)]
(is (= (rstr [:p "p:a"])
(rstr (ce c1 #js{:a "a"}))))
(is (= @a nil))
(is (= (rstr [:p "p:"])
(rstr (ce c1 #js{:a nil}))))
(is (= (rstr [:p "p:"])
@ -500,10 +503,12 @@
(is (= (rstr [:p "p:a" [:b "b"]])
(rstr (ce c1 #js{:a "a"}
(ae [:b "b"])))))
(is (= @a nil))
(is (= (rstr [:p "p:a" [:b "b"] [:i "i"]])
(rstr (ce c1 #js{:a "a"}
(ae [:b "b"])
(ae [:i "i"])))))))
(ae [:i "i"])))))
(is (= @a nil))))
(deftest test-keys
(let [a nil ;; (r/atom "a")