From 25eb682b5e1db2d6d7c10cc99ea7085180d45df8 Mon Sep 17 00:00:00 2001 From: Wee Date: Fri, 7 Dec 2018 01:07:50 +0800 Subject: [PATCH] fix: earlier onBecome(Un)Observed disposer will not dispose later listener (fix #1537) --- src/api/become-observed.ts | 36 +++++++++++++++++++++++++---- test/base/extras.js | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/src/api/become-observed.ts b/src/api/become-observed.ts index 1646991dc0..cfaaa21eb0 100644 --- a/src/api/become-observed.ts +++ b/src/api/become-observed.ts @@ -5,9 +5,19 @@ import { Lambda, ObservableMap, fail, - getAtom + getAtom, + once } from "../internal" +export interface atomListeners { + [propName: string]: { + observedListeners?: Set + unobservedListeners?: Set + } +} + +const atomsObservedListeners: atomListeners = {} + export function onBecomeObserved( value: IObservable | IComputedValue | IObservableArray | ObservableMap, listener: Lambda @@ -43,11 +53,27 @@ function interceptHook(hook: "onBecomeObserved" | "onBecomeUnobserved", thing, a if (typeof orig !== "function") return fail(process.env.NODE_ENV !== "production" && "Not an atom that can be (un)observed") - atom[hook] = function() { - orig.call(this) - cb.call(this) + const initHooks = () => { + atom[hook] = function() { + ;(atomsObservedListeners[atom.name][hook] as Set).forEach(listener => + listener() + ) + } } + + if (atomsObservedListeners[atom.name] && atomsObservedListeners[atom.name][hook]) { + ;(atomsObservedListeners[atom.name][hook] as Set).add(cb) + } else { + if (atomsObservedListeners[atom.name]) { + atomsObservedListeners[atom.name][hook] = new Set([cb]) + initHooks() + } else { + atomsObservedListeners[atom.name] = { [hook]: new Set([cb]) } + initHooks() + } + } + return function() { - atom[hook] = orig + ;(atomsObservedListeners[atom.name][hook] as Set).delete(cb) } } diff --git a/test/base/extras.js b/test/base/extras.js index 4772156a1a..770587571e 100644 --- a/test/base/extras.js +++ b/test/base/extras.js @@ -399,6 +399,53 @@ test("onBecome(Un)Observed - less simple", () => { expect(events.length).toBe(0) }) +test("onBecomeObserved correctly disposes second listener #1537", () => { + const x = mobx.observable.box(3) + const events = [] + const d1 = mobx.onBecomeObserved(x, "a", () => { + events.push("a observed") + }) + const d2 = mobx.onBecomeObserved(x, "b", () => { + events.push("b observed") + }) + d1() + mobx.reaction(() => x.get(), () => {}) + expect(events.length).toBe(1) + expect(events).toEqual(["b observed"]) +}) + +test("onBecomeObserved correctly disposes second listener #1537", () => { + const x = mobx.observable.box(3) + const events = [] + const d1 = mobx.onBecomeUnobserved(x, "a", () => { + events.push("a unobserved") + }) + const d2 = mobx.onBecomeUnobserved(x, "b", () => { + events.push("b unobserved") + }) + d1() + const d3 = mobx.reaction(() => x.get(), () => {}) + d3() + expect(events.length).toBe(1) + expect(events).toEqual(["b unobserved"]) +}) + +test("onBecomeUnobserved correctly disposes second listener #1537", () => { + const x = mobx.observable.box(3) + const events = [] + const d1 = mobx.onBecomeUnobserved(x, "a", () => { + events.push("a unobserved") + }) + const d2 = mobx.onBecomeUnobserved(x, "b", () => { + events.push("b unobserved") + }) + d1() + const d3 = mobx.reaction(() => x.get(), () => {}) + d3() + expect(events.length).toBe(1) + expect(events).toEqual(["b unobserved"]) +}) + test("deepEquals should yield correct results for complex objects #1118 - 1", () => { const d2016jan1 = new Date("2016-01-01") const d2016jan1_2 = new Date("2016-01-01")