Move update batching to util

This commit is contained in:
Dan Holmsand 2014-02-10 16:33:22 +01:00
parent 2901ab6a32
commit 81da69697e
4 changed files with 95 additions and 77 deletions

View File

@ -9,7 +9,7 @@
(def React tmpl/React)
(def is-client tmpl/isClient)
(def is-client util/isClient)
(defn render-component
"Render a Reagent component into the DOM. The first argument may be either a
@ -110,7 +110,7 @@ specially, like React's transferPropsTo."
Note that this may not work in event handlers, since React.js does
batching of updates there."
[]
(comp/flush))
(util/flush))
@ -129,7 +129,7 @@ re-rendered."
(defn next-tick
"Run f using requestAnimationFrame or equivalent."
[f]
(comp/next-tick f))
(util/next-tick f))
(defn partial
"Works just like clojure.core/partial, except that it is an IFn, and

View File

@ -1,9 +1,8 @@
(ns reagent.impl.component
(:refer-clojure :exclude [flush])
(:require [reagent.impl.template :as tmpl
:refer [cljs-argv cljs-level React]]
[reagent.impl.util :as util]
[reagent.impl.util :as util :refer [cljs-level]]
[reagent.ratom :as ratom]
[reagent.debug :refer-macros [dbg prn]]))
@ -53,55 +52,6 @@
;;; Rendering
(defn fake-raf [f]
(js/setTimeout f 16))
(def next-tick
(if-not tmpl/isClient
fake-raf
(let [w js/window]
(or (.-requestAnimationFrame w)
(.-webkitRequestAnimationFrame w)
(.-mozRequestAnimationFrame w)
(.-msRequestAnimationFrame w)
fake-raf))))
(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]
(.push queue C)
(.schedule this))
(schedule [this]
(when-not scheduled?
(set! scheduled? true)
(next-tick #(.run-queue this))))
(run-queue [_]
(let [q queue]
(set! queue (array))
(set! scheduled? false)
(run-queue q))))
(def render-queue (RenderQueue. (array) false))
(defn flush []
(.run-queue render-queue))
(defn queue-render [C]
(set! (.-cljsIsDirty C) true)
(.queue-render render-queue C))
(defn do-render [C]
(set! (.-cljsIsDirty C) false)
@ -128,20 +78,6 @@
(do-render C))
res)))))
(defn run-reactively [C run on-dirty]
(let [rat (.-cljsRatom C)]
(if (nil? rat)
(let [res (ratom/capture-derefed run C)
derefed (.-captured C)]
(when (and (not (nil? derefed))
tmpl/isClient)
(set! (.-cljsRatom C)
(ratom/make-reaction run
:auto-run on-dirty
:derefed derefed)))
res)
(ratom/run rat))))
;;; Function wrapping
@ -227,10 +163,12 @@
(defn add-render [fun-map render-f]
(assoc fun-map
:cljsRender render-f
:render (fn []
(this-as C
(run-reactively
C #(do-render C) #(queue-render C))))))
:render (if util/isClient
(fn []
(this-as C
(util/run-reactively
C #(do-render C) #(util/queue-render C))))
(fn [] (this-as C (do-render C))))))
(defn wrap-funs [fun-map]
(let [render-fun (or (:componentFunction fun-map)

View File

@ -2,16 +2,14 @@
(ns reagent.impl.template
(:require [clojure.string :as string]
[reagent.impl.reactimport :as reactimport]
[reagent.impl.util :as util]
[reagent.impl.util :as util :refer [cljs-level]]
[reagent.debug :refer-macros [dbg prn println log]]))
(def React reactimport/React)
(def cljs-argv "cljsArgv")
(def cljs-level "cljsLevel")
(def isClient (not (nil? (try (.-document js/window)
(catch js/Object e nil)))))
(def isClient util/isClient)
(def dont-camel-case #{"aria" "data"})

View File

@ -1,5 +1,67 @@
(ns reagent.impl.util
(:require [reagent.debug :refer-macros [dbg]]))
(:refer-clojure :exclude [flush])
(:require [reagent.debug :refer-macros [dbg]]
[reagent.ratom :as ratom]))
(def isClient (not (nil? (try (.-document js/window)
(catch js/Object e nil)))))
(def cljs-level "cljsLevel")
;;; Update batching
(defn fake-raf [f]
(js/setTimeout f 16))
(def next-tick
(if-not isClient
fake-raf
(let [w js/window]
(or (.-requestAnimationFrame w)
(.-webkitRequestAnimationFrame w)
(.-mozRequestAnimationFrame w)
(.-msRequestAnimationFrame w)
fake-raf))))
(defn compare-levels [c1 c2]
(- (-> c1 (aget "props") (aget cljs-level))
(-> c2 (aget "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]
(.push queue C)
(.schedule this))
(schedule [this]
(when-not scheduled?
(set! scheduled? true)
(next-tick #(.run-queue this))))
(run-queue [_]
(let [q queue]
(set! queue (array))
(set! scheduled? false)
(run-queue q))))
(def render-queue (RenderQueue. (array) false))
(defn flush []
(.run-queue render-queue))
(defn queue-render [C]
(set! (.-cljsIsDirty C) true)
(.queue-render render-queue C))
;; Misc utilities
(deftype partial-ifn [f args ^:mutable p]
IFn
@ -35,6 +97,9 @@
(assert (map? p1))
(merge-style p1 (merge-class p1 (merge p1 p2))))))
;;; Helpers for shouldComponentUpdate
(def -not-found (js-obj))
(defn shallow-equal-maps [x y]
@ -71,3 +136,20 @@
(shallow-equal-maps (v1 1) (v2 1))))
(recur (inc n))
false)))))))
;; Render helper
(defn run-reactively [C run on-dirty]
(let [rat (.-cljsRatom C)]
(if (nil? rat)
(let [res (ratom/capture-derefed run C)
derefed (.-captured C)]
(when (not (nil? derefed))
(set! (.-cljsRatom C)
(ratom/make-reaction run
:auto-run on-dirty
:derefed derefed)))
res)
(ratom/run rat))))