Try to make RCursor a bit more efficient and flexible

It now avoids unnecessary re-renderings, by comparing equality
with all its arguments, and by using a Reaction to filter out
only the changes that affects its value.

This also adds an optional setter callback, that is called instead
updating the parent atom directly.
This commit is contained in:
Dan Holmsand 2014-11-13 19:52:59 +01:00
parent 92fdf36aa5
commit 347bb4d1a3
1 changed files with 34 additions and 16 deletions

View File

@ -1,6 +1,7 @@
(ns reagent.ratom (ns reagent.ratom
(:refer-clojure :exclude [atom]) (:refer-clojure :exclude [atom])
(:require-macros [reagent.debug :refer (dbg)])) (:require-macros [reagent.debug :refer (dbg log dev?)])
(:require [reagent.impl.util :as util]))
(declare ^:dynamic *ratom-context*) (declare ^:dynamic *ratom-context*)
@ -87,33 +88,47 @@
([x] (RAtom. x nil nil nil)) ([x] (RAtom. x nil nil nil))
([x & {:keys [meta validator]}] (RAtom. x meta validator nil))) ([x & {:keys [meta validator]}] (RAtom. x meta validator nil)))
(deftype RCursor [path ratom] (declare make-reaction)
(defn peek-at [a path]
(binding [*ratom-context* nil]
(get-in @a path)))
(deftype RCursor [path ratom setf ^:mutable reaction]
IAtom IAtom
IEquiv IEquiv
(-equiv [o other] (identical? o other)) (-equiv [o other]
(and (instance? RCursor other)
(= path (.-path other))
(= ratom (.-ratom other))
(= setf (.-setf other))))
IDeref IDeref
(-deref [this] (-deref [this]
(get-in @ratom path)) (if (nil? *ratom-context*)
(get-in @ratom path)
(do
(if (nil? reaction)
(set! reaction (make-reaction #(get-in @ratom path))))
@reaction)))
IReset IReset
(-reset! [a new-value] (-reset! [a new-value]
(swap! ratom assoc-in path new-value)) (if (nil? setf)
(swap! ratom assoc-in path new-value)
(setf new-value)))
ISwap ISwap
(-swap! [a f] (-swap! [a f]
(swap! ratom update-in path f)) (-reset! a (f (peek-at ratom path))))
(-swap! [a f x] (-swap! [a f x]
(swap! ratom update-in path f x)) (-reset! a (f (peek-at ratom path) x)))
(-swap! [a f x y] (-swap! [a f x y]
(swap! ratom update-in path f x y)) (-reset! a (f (peek-at ratom path) x y)))
(-swap! [a f x y more] (-swap! [a f x y more]
(swap! ratom update-in path f x y more)) (-reset! a (apply f (peek-at ratom path) x y more)))
IMeta
(-meta [_]
(-meta ratom))
IPrintWithWriter IPrintWithWriter
(-pr-writer [a writer opts] (-pr-writer [a writer opts]
@ -136,11 +151,14 @@
(-remove-watch ratom key)) (-remove-watch ratom key))
IHash IHash
(-hash [this] (goog/getUid this))) (-hash [this] (hash [ratom path setf])))
(defn cursor (defn cursor
[path ra] ([path ra]
(RCursor. path ra)) (RCursor. path ra nil nil))
([path ra setf args]
(RCursor. path ra
(util/partial-ifn. setf args nil) nil)))
(defprotocol IDisposable (defprotocol IDisposable
(dispose! [this])) (dispose! [this]))