mirror of https://github.com/status-im/reagent.git
Batch updates properly by rendering parents before children
This commit is contained in:
parent
eb381f13bb
commit
dfe0eb41d5
|
@ -44,6 +44,7 @@ looking like this:
|
|||
{:get-initial-state (fn [this])
|
||||
:component-will-receive-props (fn [this new-props])
|
||||
:should-component-update (fn [this old-props new-props old-children new-children])
|
||||
:component-did-mount (fn [this])
|
||||
:component-did-update (fn [this old-props old-children])
|
||||
:component-will-unmount (fn [this])
|
||||
:render (fn [props children this])}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
(ns reagent.impl.component
|
||||
(:refer-clojure :exclude [flush])
|
||||
(:require [reagent.impl.template :as tmpl
|
||||
:refer [cljs-props cljs-children React]]
|
||||
:refer [cljs-props cljs-children cljs-level React]]
|
||||
[reagent.impl.util :as util]
|
||||
[reagent.ratom :as ratom]
|
||||
[reagent.debug :refer-macros [dbg prn]]))
|
||||
|
@ -51,17 +51,23 @@
|
|||
(js/requestAnimationFrame f)
|
||||
(js/setTimeout f 16)))
|
||||
|
||||
(defn run-queue [v]
|
||||
(doseq [C v]
|
||||
(when-not (.-cljsIsDirty C)
|
||||
(dbg C))
|
||||
(when (.-cljsIsDirty C)
|
||||
(.forceUpdate C))))
|
||||
(defn compare-levels [c1 c2]
|
||||
(- (-> c1 js-props (aget cljs-level))
|
||||
(-> c2 js-props (aget cljs-level))))
|
||||
|
||||
(defn run-queue [a]
|
||||
;; sort components by level, to make sure parents
|
||||
;; are rendered before children
|
||||
(.sort a compare-levels)
|
||||
(dotimes [i (alength a)]
|
||||
(let [C (aget a i)]
|
||||
(when (.-cljsIsDirty C)
|
||||
(.forceUpdate C)))))
|
||||
|
||||
(deftype RenderQueue [^:mutable queue ^:mutable scheduled?]
|
||||
Object
|
||||
(queue-render [this C]
|
||||
(set! queue (conj queue C))
|
||||
(.push queue C)
|
||||
(.schedule this))
|
||||
(schedule [this]
|
||||
(when-not scheduled?
|
||||
|
@ -69,11 +75,11 @@
|
|||
(next-tick #(.run-queue this))))
|
||||
(run-queue [_]
|
||||
(let [q queue]
|
||||
(set! queue (empty queue))
|
||||
(set! queue (array))
|
||||
(set! scheduled? false)
|
||||
(run-queue q))))
|
||||
|
||||
(def render-queue (RenderQueue. [] false))
|
||||
(def render-queue (RenderQueue. (array) false))
|
||||
|
||||
(defn flush []
|
||||
(.run-queue render-queue))
|
||||
|
@ -90,7 +96,7 @@
|
|||
;; Call render function with props, children, component
|
||||
res (f props children C)
|
||||
conv (if (vector? res)
|
||||
(tmpl/as-component res)
|
||||
(tmpl/as-component res (aget p cljs-level))
|
||||
(if (fn? res)
|
||||
(do-render C (set! (.-cljsRenderFn C) res))
|
||||
res))]
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
(def cljs-props "cljsProps")
|
||||
(def cljs-children "cljsChildren")
|
||||
(def cljs-level "cljsLevel")
|
||||
|
||||
(def isClient (not (nil? (try (.-document js/window)
|
||||
(catch js/Object e nil)))))
|
||||
|
@ -64,10 +65,10 @@
|
|||
(set-id-class objprops id-class))
|
||||
objprops))))
|
||||
|
||||
(defn map-into-array [f coll]
|
||||
(defn map-into-array [f arg coll]
|
||||
(let [a (into-array coll)]
|
||||
(dotimes [i (alength a)]
|
||||
(aset a i (f (aget a i))))
|
||||
(aset a i (f (aget a i) arg)))
|
||||
a))
|
||||
|
||||
(declare as-component)
|
||||
|
@ -75,9 +76,10 @@
|
|||
(defn wrapped-render [this comp id-class]
|
||||
(let [inprops (aget this "props")
|
||||
props (aget inprops cljs-props)
|
||||
level (aget inprops cljs-level)
|
||||
hasprops (or (nil? props) (map? props))
|
||||
jsargs (->> (aget inprops cljs-children)
|
||||
(map-into-array as-component))]
|
||||
(map-into-array as-component (inc level)))]
|
||||
(.unshift jsargs (convert-props props id-class))
|
||||
(.apply comp nil jsargs)))
|
||||
|
||||
|
@ -139,7 +141,7 @@
|
|||
(set! (.-cljsReactClass tag) (wrap-component tag nil nil))
|
||||
(fn-to-class tag)))))))
|
||||
|
||||
(defn vec-to-comp [v]
|
||||
(defn vec-to-comp [v level]
|
||||
(assert (pos? (count v)))
|
||||
(let [[tag props] v
|
||||
hasmap (map? props)
|
||||
|
@ -147,14 +149,17 @@
|
|||
c (as-class tag)
|
||||
jsprops (js-obj cljs-props (if hasmap props)
|
||||
cljs-children (if (> (count v) first-child)
|
||||
(subvec v first-child)))]
|
||||
(subvec v first-child))
|
||||
cljs-level level)]
|
||||
(when hasmap
|
||||
(let [key (:key props)]
|
||||
(when-not (nil? key)
|
||||
(aset jsprops "key" key))))
|
||||
(c jsprops)))
|
||||
|
||||
(defn as-component [x]
|
||||
(cond (vector? x) (vec-to-comp x)
|
||||
(seq? x) (map-into-array as-component x)
|
||||
true x))
|
||||
(defn as-component
|
||||
([x] (as-component x 0))
|
||||
([x level]
|
||||
(cond (vector? x) (vec-to-comp x level)
|
||||
(seq? x) (map-into-array as-component level x)
|
||||
true x)))
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
(def isClient (not (nil? (try (.-document js/window)
|
||||
(catch js/Object e nil)))))
|
||||
|
||||
(def rflush reagent/flush)
|
||||
|
||||
(defn add-test-div [name]
|
||||
(let [doc js/document
|
||||
body (.-body js/document)
|
||||
|
@ -124,6 +126,40 @@
|
|||
(is (= runs (running)))
|
||||
(is (= 2 @ran)))))
|
||||
|
||||
(deftest batched-update-test []
|
||||
(when isClient
|
||||
(let [ran (atom 0)
|
||||
v1 (atom 0)
|
||||
v2 (atom 0)
|
||||
c2 (fn [{val :val}]
|
||||
(swap! ran inc)
|
||||
(assert (= @v1 val))
|
||||
[:div @v2])
|
||||
c1 (fn []
|
||||
(swap! ran inc)
|
||||
[:div @v1
|
||||
[c2 {:val @v1}]])]
|
||||
(with-mounted-component [c1]
|
||||
(fn [c div]
|
||||
(rflush)
|
||||
(is (= @ran 2))
|
||||
(swap! v2 inc)
|
||||
(is (= @ran 2))
|
||||
(rflush)
|
||||
(is (= @ran 3))
|
||||
(swap! v1 inc)
|
||||
(rflush)
|
||||
(is (= @ran 5))
|
||||
(swap! v2 inc)
|
||||
(swap! v1 inc)
|
||||
(rflush)
|
||||
(is (= @ran 7))
|
||||
(swap! v1 inc)
|
||||
(swap! v1 inc)
|
||||
(swap! v2 inc)
|
||||
(rflush)
|
||||
(is (= @ran 9)))))))
|
||||
|
||||
(deftest init-state-test
|
||||
(when isClient
|
||||
(let [ran (atom 0)
|
||||
|
|
Loading…
Reference in New Issue