mirror of https://github.com/status-im/reagent.git
Wrap different React classes in distinct wrappers
That should improve performance a little, and help React's diffing
This commit is contained in:
parent
dd3f9b10e1
commit
11a1c62024
|
@ -15,23 +15,6 @@
|
||||||
camels (map string/capitalize (rest words))]
|
camels (map string/capitalize (rest words))]
|
||||||
(apply str (first words) camels)))
|
(apply str (first words) camels)))
|
||||||
|
|
||||||
;; From Weavejester's Hiccup, via pump:
|
|
||||||
;; https://github.com/weavejester/hiccup/blob/master/src/hiccup/compiler.clj#L32
|
|
||||||
(def ^{:doc "Regular expression that parses a CSS-style id and class
|
|
||||||
from a tag name."
|
|
||||||
:private true}
|
|
||||||
re-tag #"([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?")
|
|
||||||
|
|
||||||
(def DOM (aget React "DOM"))
|
|
||||||
|
|
||||||
(defn parse-tag [tag]
|
|
||||||
(let [[tag id class] (->> tag name (re-matches re-tag) next)
|
|
||||||
comp (aget DOM tag)
|
|
||||||
class' (when class
|
|
||||||
(string/replace class #"\." " "))]
|
|
||||||
[comp (when (or id class')
|
|
||||||
[id class'])]))
|
|
||||||
|
|
||||||
(def attr-aliases {"class" "className"
|
(def attr-aliases {"class" "className"
|
||||||
"for" "htmlFor"
|
"for" "htmlFor"
|
||||||
"charset" "charSet"})
|
"charset" "charSet"})
|
||||||
|
@ -73,31 +56,82 @@
|
||||||
(set-tag-extra objprops extra))
|
(set-tag-extra objprops extra))
|
||||||
objprops))))
|
objprops))))
|
||||||
|
|
||||||
|
(defn map-into-array [f coll]
|
||||||
|
(let [a (into-array coll)
|
||||||
|
len (alength a)]
|
||||||
|
(dotimes [i len]
|
||||||
|
(aset a i (f (aget a i))))
|
||||||
|
a))
|
||||||
|
|
||||||
|
(declare as-component)
|
||||||
|
|
||||||
(declare wrapper)
|
(defn wrapped-render [this comp extra]
|
||||||
|
(let [inprops (aget this "props")
|
||||||
|
args (.-cljsArgs inprops)
|
||||||
|
[_ scnd] args
|
||||||
|
hasprops (or (nil? scnd) (map? scnd))
|
||||||
|
jsprops (convert-props (if hasprops scnd) extra)
|
||||||
|
jsargs (->> args
|
||||||
|
(drop (if hasprops 2 1))
|
||||||
|
(map-into-array as-component))]
|
||||||
|
(.apply comp nil (.concat (array jsprops) jsargs))))
|
||||||
|
|
||||||
|
(defn wrapped-should-update [C nextprops nextstate]
|
||||||
|
(let [a1 (-> C (aget "props") .-cljsArgs)
|
||||||
|
a2 (-> nextprops .-cljsArgs)]
|
||||||
|
(not (util/equal-args a1 a2))))
|
||||||
|
|
||||||
|
(defn wrap-component [comp extras]
|
||||||
|
(let [spec #js {:render #(this-as C (wrapped-render C comp extras))
|
||||||
|
:shouldComponentUpdate
|
||||||
|
#(this-as C (wrapped-should-update C %1 %2))}]
|
||||||
|
(.createClass React spec)))
|
||||||
|
|
||||||
|
;; From Weavejester's Hiccup, via pump:
|
||||||
|
;; https://github.com/weavejester/hiccup/blob/master/src/hiccup/compiler.clj#L32
|
||||||
|
(def ^{:doc "Regular expression that parses a CSS-style id and class
|
||||||
|
from a tag name."
|
||||||
|
:private true}
|
||||||
|
re-tag #"([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?")
|
||||||
|
|
||||||
|
(def DOM (aget React "DOM"))
|
||||||
|
|
||||||
|
(defn parse-tag [tag]
|
||||||
|
(let [[tag id class] (->> tag name (re-matches re-tag) next)
|
||||||
|
comp (aget DOM tag)
|
||||||
|
class' (when class
|
||||||
|
(string/replace class #"\." " "))]
|
||||||
|
[comp (when (or id class')
|
||||||
|
[id class'])]))
|
||||||
|
|
||||||
|
(defn get-wrapper [tag]
|
||||||
|
(let [[comp extra] (parse-tag tag)]
|
||||||
|
(wrap-component comp extra)))
|
||||||
|
|
||||||
|
(def cached-wrapper (memoize get-wrapper))
|
||||||
|
|
||||||
(defn fn-to-class [f]
|
(defn fn-to-class [f]
|
||||||
(assert (fn? f))
|
(assert (fn? f))
|
||||||
(let [spec (meta f)
|
(let [spec (meta f)
|
||||||
withrender (merge spec {:render f})
|
withrender (merge spec {:render f})
|
||||||
res (cloact.core/create-class withrender)]
|
res (cloact.core/create-class withrender)
|
||||||
(set! (.-cljsReactClass f) (.-cljsReactClass res))
|
wrapf (.-cljsReactClass res)]
|
||||||
res))
|
(set! (.-cljsReactClass f) wrapf)
|
||||||
|
wrapf))
|
||||||
|
|
||||||
(defn as-class [x]
|
(defn as-class [x]
|
||||||
(cond
|
(cond
|
||||||
(keyword? x) wrapper
|
(keyword? x) (cached-wrapper x)
|
||||||
(not (nil? (.-cljsReactClass x))) x
|
(not (nil? (.-cljsReactClass x))) (.-cljsReactClass x)
|
||||||
:else (do (assert (fn? x))
|
:else (do (assert (fn? x))
|
||||||
(if (.isValidClass React x)
|
(if (.isValidClass React x)
|
||||||
wrapper
|
(set! (.-cljsReactClass x) (wrap-component x nil))
|
||||||
(fn-to-class x)))))
|
(fn-to-class x)))))
|
||||||
|
|
||||||
(defn vec-to-comp [v]
|
(defn vec-to-comp [v]
|
||||||
(assert (pos? (count v)))
|
(assert (pos? (count v)))
|
||||||
(let [[tag props] v
|
(let [[tag props] v
|
||||||
c (.-cljsReactClass (as-class tag))
|
c (as-class tag)
|
||||||
obj (js-obj)]
|
obj (js-obj)]
|
||||||
(set! (.-cljsArgs obj) v)
|
(set! (.-cljsArgs obj) v)
|
||||||
(when (map? props)
|
(when (map? props)
|
||||||
|
@ -106,44 +140,7 @@
|
||||||
(set! (.-key obj) key))))
|
(set! (.-key obj) key))))
|
||||||
(c obj)))
|
(c obj)))
|
||||||
|
|
||||||
(defn map-into-array [f coll]
|
|
||||||
(let [a (into-array coll)
|
|
||||||
len (alength a)]
|
|
||||||
(dotimes [i len]
|
|
||||||
(aset a i (f (aget a i))))
|
|
||||||
a))
|
|
||||||
|
|
||||||
(defn as-component [x]
|
(defn as-component [x]
|
||||||
(cond (vector? x) (vec-to-comp x)
|
(cond (vector? x) (vec-to-comp x)
|
||||||
(seq? x) (map-into-array as-component x)
|
(seq? x) (map-into-array as-component x)
|
||||||
true x))
|
true x))
|
||||||
|
|
||||||
(def cached-tag (memoize parse-tag))
|
|
||||||
|
|
||||||
(defn render-wrapped [this]
|
|
||||||
(let [inprops (aget this "props")
|
|
||||||
args (.-cljsArgs inprops)
|
|
||||||
[tag scnd] args
|
|
||||||
hasprops (or (nil? scnd) (map? scnd))
|
|
||||||
[native extra] (when (keyword? tag) (cached-tag tag))
|
|
||||||
f (or native tag)
|
|
||||||
jsprops (convert-props (when hasprops scnd) extra)
|
|
||||||
jsargs (->> args
|
|
||||||
(drop (if hasprops 2 1))
|
|
||||||
(map-into-array as-component))]
|
|
||||||
(assert (.isValidClass React f))
|
|
||||||
(assert (nil? (.-cljsReactClass f)))
|
|
||||||
(.apply f nil (.concat (array jsprops) jsargs))))
|
|
||||||
|
|
||||||
(defn should-update-wrapped [C nextprops nextstate]
|
|
||||||
(let [a1 (-> C (aget "props") .-cljsArgs)
|
|
||||||
a2 (-> nextprops .-cljsArgs)]
|
|
||||||
(not (util/equal-args a1 a2))))
|
|
||||||
|
|
||||||
(def wrapper
|
|
||||||
(.createClass React (js-obj "render"
|
|
||||||
#(this-as C (render-wrapped C))
|
|
||||||
"shouldComponentUpdate"
|
|
||||||
#(this-as C (should-update-wrapped C %1 %2)))))
|
|
||||||
|
|
||||||
(set! (.-cljsReactClass wrapper) wrapper)
|
|
||||||
|
|
|
@ -51,10 +51,10 @@
|
||||||
(defn equal-args [v1 v2]
|
(defn equal-args [v1 v2]
|
||||||
;; Compare two "args" vectors, i.e things like [:div {:foo "bar} "baz"],
|
;; Compare two "args" vectors, i.e things like [:div {:foo "bar} "baz"],
|
||||||
;; using identical? on all individual parts.
|
;; using identical? on all individual parts.
|
||||||
|
;; The first bit (e.g the :div is assumed to be identical).
|
||||||
(or (identical? v1 v2)
|
(or (identical? v1 v2)
|
||||||
(let [c1 (count v1)]
|
(let [c1 (count v1)]
|
||||||
(and (= (nth v1 0) (nth v2 0)) ; may be symbol or fn
|
(and (identical? c1 (count v2))
|
||||||
(identical? c1 (count v2))
|
|
||||||
(if (< c1 2)
|
(if (< c1 2)
|
||||||
true
|
true
|
||||||
(let [props1 (nth v1 1)]
|
(let [props1 (nth v1 1)]
|
||||||
|
|
Loading…
Reference in New Issue