                                      (cb key self old' new')))))))
      (removeWatch [_ key]
        (let [key (prefix-key key id)]
-         (remove-watch source key))))
+         (remove-watch src key))))
 
    :cljs
-   (deftype RWFocus [id lens source check-equals?]
+   (deftype RWFocus [id lens src srccache cache check-equals?]
      IAtom
      IDeref
-     (-deref [_] (focus lens @source))
+     (-deref [_]
+       (letfn [(generate []
+                 (let [source (deref src)
+                       result (focus lens source)]
+                   (vreset! srccache source)
+                   (vreset! cache result)
+                   result))]
+         (if (identical? @cache +empty+)
+           (generate)
+           (if (identical? @srccache @src)
+             @cache
+             (generate)))))
 
      IReset
      (-reset! [self newval]
-       (swap! source #(put lens newval %))
+       (swap! src #(put lens newval %))
        (deref self))
 
      ISwap
      (-swap! [self f]
-       (swap! source (fn [s] (over lens f s)))
+       (swap! src (fn [s] (over lens f s)))
        (deref self))
      (-swap! [self f x]
-       (swap! source (fn [s] (over lens #(f % x) s)))
+       (swap! src (fn [s] (over lens #(f % x) s)))
        (deref self))
      (-swap! [self f x y]
-       (swap! source (fn [s] (over lens #(f % x y) s)))
+       (swap! src (fn [s] (over lens #(f % x y) s)))
        (deref self))
      (-swap! [self f x y more]
-       (swap! source (fn [s] (over lens #(apply f % x y more) s)))
+       (swap! src (fn [s] (over lens #(apply f % x y more) s)))
        (deref self))
 
      IWatchable
      (-add-watch [self key cb]
        (let [key (prefix-key key id)]
-         (add-watch source key (fn [key _ oldval newval]
+         (add-watch src key (fn [key _ oldval newval]
                                  (let [old' (focus lens oldval)
                                        new' (focus lens newval)]
                                    (when (or (not check-equals?)

  [key id]
  (keyword (str id "-" (name key))))

#?(:clj
   (deftype RWFocus [id lens source check-equals?]
     clojure.lang.IDeref
     (deref [_] (focus lens @source))

     clojure.lang.IAtom
     (reset [self newval]
       (swap! source #(put lens newval %))
       (deref self))
     (swap [self f]
       (swap! source (fn [s] (over lens f s)))
       (deref self))
     (swap [self f x]
       (swap! source (fn [s] (over lens #(f % x) s)))
       (deref self))
     (swap [self f x y]
       (swap! source (fn [s] (over lens #(f % x y) s)))
       (deref self))
     (swap [self f x y more]
       (swap! source (fn [s] (over lens #(apply f % x y more) s)))
       (deref self))

     clojure.lang.IRef
     (addWatch [self key cb]
       (let [key (prefix-key key id)]
         (add-watch source key (fn [key _ oldval newval]
                                 (let [old' (focus lens oldval)
                                       new' (focus lens newval)]
                                   (when (or (not check-equals?)

                                     (cb key self old' new')))))))
     (removeWatch [_ key]
       (let [key (prefix-key key id)]
         (remove-watch src key))))

   :cljs
   (deftype ROFocus [id lens src srccache cache check-equals?]
     IDeref
     (-deref [_]
       (letfn [(generate []
                 (let [source (deref src)
                       result (focus lens source)]
                   (vreset! srccache source)
                   (vreset! cache result)
                   result))]
         (if (identical? @cache +empty+)
           (generate)
           (if (identical? @srccache @src)
             @cache
             (generate)))))

     IWatchable
     (-add-watch [self key cb]
       (let [key (prefix-key key id)]
         (add-watch src key (fn [key _ oldval newval]
                                 (let [old' (focus lens oldval)
                                       new' (focus lens newval)]
                                   (when (or (not check-equals?)
