diff --git a/demo/reagentdemo/common.cljs b/demo/reagentdemo/common.cljs index b3917d2..7d12cd1 100644 --- a/demo/reagentdemo/common.cljs +++ b/demo/reagentdemo/common.cljs @@ -39,7 +39,8 @@ [:div.demo-example [:a.demo-example-hide {:on-click (fn [e] (.preventDefault e) - (swap! showing not))} + (swap! showing not) + false)} (if @showing "hide" "show")] [:h3.demo-heading "Example "] (when @showing diff --git a/project.clj b/project.clj index 6a9c215..95b9a3b 100644 --- a/project.clj +++ b/project.clj @@ -1,5 +1,5 @@ -(defproject reagent "0.2.1" +(defproject reagent "0.3.0-SNAPSHOT" :url "http://github.com/holmsand/reagent" :license {:name "MIT"} :description "A simple ClojureScript interface to React" diff --git a/src/reagent/core.cljs b/src/reagent/core.cljs index f5c70b1..9306331 100644 --- a/src/reagent/core.cljs +++ b/src/reagent/core.cljs @@ -1,6 +1,6 @@ (ns reagent.core - (:refer-clojure :exclude [partial atom]) + (:refer-clojure :exclude [partial atom flush]) (:require-macros [reagent.debug :refer [dbg prn]]) (:require [reagent.impl.template :as tmpl] [reagent.impl.component :as comp] @@ -105,6 +105,10 @@ specially, like React's transferPropsTo." [defaults props] (util/merge-props defaults props)) +(defn flush [] + (comp/flush)) + + ;; Ratom diff --git a/src/reagent/impl/component.cljs b/src/reagent/impl/component.cljs index d9964d3..eaaf0d1 100644 --- a/src/reagent/impl/component.cljs +++ b/src/reagent/impl/component.cljs @@ -1,5 +1,6 @@ (ns reagent.impl.component + (:refer-clojure :exclude [flush]) (:require [reagent.impl.template :as tmpl :refer [cljs-props cljs-children React]] [reagent.impl.util :as util] @@ -43,10 +44,46 @@ (defn set-props [C newprops] (replace-props C (merge (get-props C) newprops))) +;;; Rendering -;;; Function wrapping +(defn next-tick [f] + (if (.-requestAnimationFrame js/window) + (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)))) + +(deftype RenderQueue [^:mutable queue ^:mutable scheduled?] + Object + (queue-render [this C] + (set! queue (conj queue C)) + (.schedule this)) + (schedule [this] + (when-not scheduled? + (set! scheduled? true) + (next-tick #(.run-queue this)))) + (run-queue [_] + (let [q queue] + (set! queue (empty queue)) + (set! scheduled? false) + (run-queue q)))) + +(def render-queue (RenderQueue. [] false)) + +(defn flush [] + (.run-queue render-queue)) + +(defn queue-render [C] + (set! (.-cljsIsDirty C) true) + (.queue-render render-queue C)) (defn do-render [C f] + (set! (.-cljsIsDirty C) false) (let [p (js-props C) props (props-in-props p) children (aget p cljs-children) @@ -66,10 +103,13 @@ (ratom/make-reaction #(do-render C (.-cljsRenderFn C)) :auto-run (if tmpl/isClient - #(.forceUpdate C) - identity)))) + #(queue-render C) + identity)))) (ratom/run (.-cljsRatom C))) + +;;; Function wrapping + (defn custom-wrapper [key f] (case key :getDefaultProps @@ -108,6 +148,7 @@ :componentWillUnmount (fn [C] (ratom/dispose! (.-cljsRatom C)) + (set! (.-cljsIsDirty C) false) (when f (f C))) :render diff --git a/test/testcloact.cljs b/test/testcloact.cljs index 5b3e65d..2235f55 100644 --- a/test/testcloact.cljs +++ b/test/testcloact.cljs @@ -95,27 +95,34 @@ (let [ran (atom 0) runs (running) val (atom 0) + secval (atom 0) v1 (reaction @val) comp (fn [] (swap! ran inc) - [:div (str "val " @v1)])] + [:div (str "val " @v1 @val @secval)])] (with-mounted-component [comp] (fn [C div] - (swap! ran inc) + (reagent/flush) (is (not= runs (running))) (is (found-in #"val 0" div)) - (is (= 2 @ran)) + (is (= 1 @ran)) + (reset! secval 1) + (reset! secval 0) (reset! val 1) + (reset! val 2) + (reset! val 1) + (reagent/flush) (is (found-in #"val 1" div)) - (is (= 3 @ran)) + (is (= 2 @ran)) ;; should not be rendered (reset! val 1) + (reagent/flush) (is (found-in #"val 1" div)) - (is (= 3 @ran)))) + (is (= 2 @ran)))) (is (= runs (running))) - (is (= 3 @ran))))) + (is (= 2 @ran))))) (deftest init-state-test (when isClient