Skip to content

Commit

Permalink
fix unmount bug
Browse files Browse the repository at this point in the history
  • Loading branch information
dehli committed Jul 11, 2024
1 parent ab2a826 commit 8cb117c
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 18 deletions.
2 changes: 1 addition & 1 deletion core/src/refx/hooks.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
(react/useMemo
(fn []
[(fn [callback]
(let [key {:index (swap! use-sub-counter inc)}]
(let [key {::subs/index (swap! use-sub-counter inc)}]
(subs/-add-listener sub key callback)
#(subs/-remove-listener sub key)))
(fn []
Expand Down
37 changes: 26 additions & 11 deletions core/src/refx/subs.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

(def kind :sub)

(defn ui-sub?
"UI subscriptions are batched together and invoked after all subs
finish computing their new values. This is done to reduce renders and
prevent consumers from having an inconsistent view of the DB."
[sub-key]
(some? (::index sub-key)))

;; --- signals ----------------------------------------------------------------

(defprotocol ISignal
Expand Down Expand Up @@ -78,7 +85,7 @@

(defonce ^:private listeners-state
(letfn [(comparator [a b]
(compare (:index a) (:index b)))]
(compare (::index a) (::index b)))]
(atom {:counter 0 :pending (sorted-map-by comparator)})))

(defn- invoke-listener
Expand All @@ -103,16 +110,20 @@

(interop/next-tick
(fn []
(let [listener-fns (atom nil)]
(swap! listeners-state (fn [state]
(let [{:keys [counter pending] :as new-state}
(update state :counter dec)]
(if (zero? counter)
(do (reset! listener-fns pending)
(update new-state :pending empty))
new-state))))
(doseq [[_ f] @listener-fns]
(f)))))))
(let [{:keys [counter pending]}
(swap! listeners-state update :counter dec)]

(when (zero? counter)
(doseq [[listener-key _] pending]
;; Triggering a listener-fn can result in a subsequent sub's
;; remove-listener to be called (which will remove it from pending).
;; This check ensure it's still pending.
(let [listener-fn (atom nil)]
(swap! listeners-state (fn [state]
(reset! listener-fn (get-in state [:pending listener-key]))
(update state :pending dissoc listener-key)))
(when-let [f @listener-fn]
(f))))))))))

(deftype Listeners [^:mutable listeners]
Object
Expand Down Expand Up @@ -160,6 +171,8 @@
(-add-listener [_ k f]
(.add listeners k f))
(-remove-listener [this k]
(when (ui-sub? k)
(swap! listeners-state update :pending dissoc k))
(.remove listeners k)
(when (.empty? listeners)
(sub-orphaned this)))
Expand Down Expand Up @@ -238,6 +251,8 @@
(-add-listener [_ k f]
(.add listeners k f))
(-remove-listener [this k]
(when (ui-sub? k)
(swap! listeners-state update :pending dissoc k))
(.remove listeners k)
(when (.empty? listeners)
(sub-orphaned this)))
Expand Down
12 changes: 6 additions & 6 deletions core/test/refx/subs_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
listener-calls (atom [])
remove-listener-fns (atom '())
add-listener! (fn [sub]
(let [key {:index (swap! listener-count inc)}]
(let [key {::subs/index (swap! listener-count inc)}]
(subs/-add-listener sub key #(swap! listener-calls conj key))
(swap! remove-listener-fns conj #(subs/-remove-listener sub key))))
remove-listeners! (fn []
Expand All @@ -130,13 +130,13 @@
(add-listener! sub-c)
(add-listener! sub-d)
(reset! source 1)
(remove-listeners!)
(async done
(js/setTimeout (fn []
(remove-listeners!)
(is (= @listener-calls
[{:index 1}
{:index 2}
{:index 3}
{:index 4}]))
[{::subs/index 1}
{::subs/index 2}
{::subs/index 3}
{::subs/index 4}]))
(done))
10)))))

0 comments on commit 8cb117c

Please sign in to comment.