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
(: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*)
@ -87,33 +88,47 @@
([x] (RAtom. x nil nil 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
IEquiv
(-equiv [o other] (identical? o other))
(-equiv [o other]
(and (instance? RCursor other)
(= path (.-path other))
(= ratom (.-ratom other))
(= setf (.-setf other))))
IDeref
(-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
(-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
(-swap! [a f]
(swap! ratom update-in path f))
(-reset! a (f (peek-at ratom path))))
(-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! ratom update-in path f x y))
(-reset! a (f (peek-at ratom path) x y)))
(-swap! [a f x y more]
(swap! ratom update-in path f x y more))
IMeta
(-meta [_]
(-meta ratom))
(-reset! a (apply f (peek-at ratom path) x y more)))
IPrintWithWriter
(-pr-writer [a writer opts]
@ -136,11 +151,14 @@
(-remove-watch ratom key))
IHash
(-hash [this] (goog/getUid this)))
(-hash [this] (hash [ratom path setf])))
(defn cursor
[path ra]
(RCursor. path ra))
([path ra]
(RCursor. path ra nil nil))
([path ra setf args]
(RCursor. path ra
(util/partial-ifn. setf args nil) nil)))
(defprotocol IDisposable
(dispose! [this]))