diff --git a/src/cloact/impl/component.cljs b/src/cloact/impl/component.cljs index c0836d0..9b5f221 100644 --- a/src/cloact/impl/component.cljs +++ b/src/cloact/impl/component.cljs @@ -23,39 +23,21 @@ (defn state [this] (.-cljsState this)) -;; We store the "args" (i.e a vector like [comp props child1]) -;; in .-cljsArgs, with optional props, which makes access a bit -;; tricky. The upside is that we don't have to do any allocations. - -(defn args-of [C] - (-> C (aget "props") .-cljsArgs)) - -(defn props-in-args [args] - (let [p (nth args 1 nil)] - (when (map? p) p))) +(defn js-props [C] + (aget C "props")) (defn props-in-props [props] - (-> props .-cljsArgs props-in-args)) + (-> props .-cljsProps)) -(defn- first-child [args] - (let [p (nth args 1 nil)] - (if (or (nil? p) (map? p)) 2 1))) - -(defn- cljs-props [C] - (-> C args-of props-in-args)) +(defn cljs-props [C] + (-> C js-props props-in-props)) (defn get-children [C] - (let [args (args-of C) - c (first-child args)] - (drop c args))) + (-> C js-props .-cljsChildren)) (defn replace-props [C newprops] (let [obj (js-obj)] - (set! (.-cljsArgs obj) - (apply vector - (nth (args-of C) 0) - newprops - (get-children C))) + (set! (.-cljsProps obj) newprops) (.setProps C obj))) (defn set-props [C newprops] @@ -105,13 +87,15 @@ (fn [C nextprops nextstate] ;; Don't care about nextstate here, we use forceUpdate ;; when only when state has changed anyway. - (let [a1 (args-of C) - a2 (-> nextprops .-cljsArgs)] - (assert (vector? a1)) + (let [inprops (aget C "props") + p1 (.-cljsProps inprops) + c1 (.-cljsChildren inprops) + p2 (.-cljsProps nextprops) + c2 (.-cljsChildren nextprops)] (if (nil? f) - (not (util/equal-args a1 a2)) - ;; Call f with oldprops, newprops - (f (props-in-args a1) (props-in-args a2))))) + (not (util/equal-args p1 c1 p2 c2)) + ;; call f with oldprops newprops oldchildren newchildren + (f p1 p2 c1 c2)))) :componentWillUnmount (fn [C] @@ -170,8 +154,14 @@ (let [spec (cljsify body) res (.createClass React spec) f (fn [& args] - (let [arg (js-obj)] - (set! (.-cljsArgs arg) (apply vector res args)) + (let [arg (js-obj) + props (nth args 0 nil) + hasmap (map? props) + first-child (if (or hasmap (nil? props)) 1 0)] + (set! (.-cljsProps arg) (if hasmap props {})) + (set! (.-cljsChildren arg) + (if (> (count args) first-child) + (subvec args first-child))) (res arg)))] (set! (.-cljsReactClass f) res) (set! (.-cljsReactClass res) res) diff --git a/src/cloact/impl/template.cljs b/src/cloact/impl/template.cljs index 7ad50da..5bbf568 100644 --- a/src/cloact/impl/template.cljs +++ b/src/cloact/impl/template.cljs @@ -65,18 +65,20 @@ (defn wrapped-render [this comp id-class] (let [inprops (aget this "props") - args (.-cljsArgs inprops) - props (nth args 1 nil) + props (.-cljsProps inprops) hasprops (or (nil? props) (map? props)) - jsargs (->> (if hasprops (drop 1 args) args) + jsargs (->> (.-cljsChildren inprops) (map-into-array as-component))] - (aset jsargs 0 (convert-props (if hasprops props) id-class)) + (.unshift jsargs (convert-props props id-class)) (.apply comp nil jsargs))) (defn wrapped-should-update [C nextprops nextstate] - (let [a1 (-> C (aget "props") .-cljsArgs) - a2 (-> nextprops .-cljsArgs)] - (not (util/equal-args a1 a2)))) + (let [inprops (aget C "props") + p1 (.-cljsProps inprops) + c1 (.-cljsChildren inprops) + p2 (.-cljsProps nextprops) + c2 (.-cljsChildren nextprops)] + (not (util/equal-args p1 c1 p2 c2)))) (defn wrap-component [comp extras] (.createClass React (js-obj "render" @@ -129,10 +131,15 @@ (defn vec-to-comp [v] (assert (pos? (count v))) (let [[tag props] v + hasmap (map? props) + first-child (if (or hasmap (nil? props)) 2 1) c (as-class tag) jsprops (js-obj)] - (set! (.-cljsArgs jsprops) v) - (when (map? props) + (set! (.-cljsProps jsprops) (if hasmap props {})) + (set! (.-cljsChildren jsprops) + (if (> (count v) first-child) + (subvec v first-child))) + (when hasmap (let [key (:key props)] (when-not (nil? key) (aset jsprops "key" key)))) diff --git a/src/cloact/impl/util.cljs b/src/cloact/impl/util.cljs index d40bc28..e361016 100644 --- a/src/cloact/impl/util.cljs +++ b/src/cloact/impl/util.cljs @@ -1,4 +1,5 @@ -(ns cloact.impl.util) +(ns cloact.impl.util + (:require [cloact.debug :refer-macros [dbg]])) (deftype partial-ifn [f args ^:mutable p] IFn @@ -34,46 +35,38 @@ (assert (map? p1)) (merge-style p1 (merge-class p1 (merge p1 p2)))))) -(defn identical-parts [v1 v2 from] - ;; Compare two vectors, from item with index "from", using identical? - (let [end (count v1)] - (loop [n from] - (if (>= n end) - true - (if (identical? (nth v1 n) (nth v2 n)) - (recur (inc n)) - false))))) +(defn identical-parts [v1 v2] + ;; Compare two vectors using identical? + (or (identical? v1 v2) + (let [end (count v1)] + (and (== end (count v2)) + (loop [n 0] + (if (>= n end) + true + (if (identical? (nth v1 n) (nth v2 n)) + (recur (inc n)) + false))))))) (def -not-found (js-obj)) (defn shallow-equal-maps [x y] ;; Compare two maps, using keyword-identical? on all values (or (identical? x y) - (when (== (count x) (count y)) - (reduce-kv (fn [res k v] - (let [yv (get y k -not-found)] - (if (or (keyword-identical? v yv) - ;; hack to allow cloact.core/partial and :style - ;; maps to be compared with = - (and (or - (keyword-identical? k :style) - (identical? (type v) partial-ifn)) - (= v yv))) - res - (reduced false)))) - true x)))) + (and (== (count x) (count y)) + (reduce-kv (fn [res k v] + (let [yv (get y k -not-found)] + (if (or (keyword-identical? v yv) + ;; hack to allow cloact.core/partial and :style + ;; maps to be compared with = + (and (or + (keyword-identical? k :style) + (identical? (type v) partial-ifn)) + (= v yv))) + res + (reduced false)))) + true x)))) -(defn equal-args [v1 v2] - ;; Compare two "args" vectors, i.e things like [:div {:foo "bar} "baz"], - ;; using identical? on all individual parts. - ;; The first bit (e.g the :div is assumed to be identical). - (or (identical? v1 v2) - (let [c1 (count v1)] - (and (== c1 (count v2)) - (if (< c1 2) - true - (let [props1 (nth v1 1)] - (if (or (nil? props1) (map? props1)) - (and (identical-parts v1 v2 2) - (shallow-equal-maps props1 (nth v2 1))) - (identical-parts v1 v2 1)))))))) +(defn equal-args [p1 c1 p2 c2] + [p1 c1 p2 c2] + (and (identical-parts c1 c2) + (shallow-equal-maps p1 p2)))