From 75db6be1eb25500a2f9a249cdaeb220836dfef74 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 4 Aug 2021 17:02:24 +0200 Subject: [PATCH 1/2] feat: destroy a store with $dispose Close #557 --- packages/pinia/__tests__/store.spec.ts | 23 +++++++++++++++++++++++ packages/pinia/src/devtools/plugin.ts | 11 ++++++++++- packages/pinia/src/store.ts | 8 ++++++++ packages/pinia/src/types.ts | 8 ++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/pinia/__tests__/store.spec.ts b/packages/pinia/__tests__/store.spec.ts index 7e8d173107..705fbe39df 100644 --- a/packages/pinia/__tests__/store.spec.ts +++ b/packages/pinia/__tests__/store.spec.ts @@ -303,4 +303,27 @@ describe('Store', () => { expect(One.text()).toBe('1') expect(Two.text()).toBe('1') }) + + it('can be disposed', () => { + const pinia = createPinia() + const useStore = defineStore({ + id: 'main', + state: () => ({ n: 0 }), + }) + + const store = useStore(pinia) + const spy = jest.fn() + + store.$subscribe(spy) + pinia.state.value.main.n++ + expect(spy).toHaveBeenCalledTimes(1) + + expect(useStore()).toBe(store) + store.$dispose() + pinia.state.value.main.n++ + + expect(spy).toHaveBeenCalledTimes(1) + + expect(useStore()).not.toBe(store) + }) }) diff --git a/packages/pinia/src/devtools/plugin.ts b/packages/pinia/src/devtools/plugin.ts index 0ca6bf8146..04fd9d001b 100644 --- a/packages/pinia/src/devtools/plugin.ts +++ b/packages/pinia/src/devtools/plugin.ts @@ -414,11 +414,20 @@ function addStoreToDevtools(app: App, store: StoreGeneric) { api.sendInspectorState(INSPECTOR_ID) }) + const { $dispose } = store + store.$dispose = () => { + $dispose() + api.notifyComponentUpdate() + api.sendInspectorTree(INSPECTOR_ID) + api.sendInspectorState(INSPECTOR_ID) + toastMessage(`Disposed "${store.$id}" store 🗑`) + } + // trigger an update so it can display new registered stores api.notifyComponentUpdate() api.sendInspectorTree(INSPECTOR_ID) api.sendInspectorState(INSPECTOR_ID) - toastMessage(`"${store.$id}" store installed`) + toastMessage(`"${store.$id}" store installed 🆕`) } ) } diff --git a/packages/pinia/src/store.ts b/packages/pinia/src/store.ts index c9b9428c0d..aca79319d9 100644 --- a/packages/pinia/src/store.ts +++ b/packages/pinia/src/store.ts @@ -269,6 +269,13 @@ function createSetupStore< } : noop + function $dispose() { + scope.stop() + subscriptions = [] + actionSubscriptions = [] + pinia._s.delete($id) + } + /** * Wraps an action to handle subscriptions. * @@ -448,6 +455,7 @@ function createSetupStore< return removeSubscription }, + $dispose, } as StoreWithState const store: Store = reactive( diff --git a/packages/pinia/src/types.ts b/packages/pinia/src/types.ts index c5a5ff8697..afc1872b27 100644 --- a/packages/pinia/src/types.ts +++ b/packages/pinia/src/types.ts @@ -414,6 +414,14 @@ export interface StoreWithState< callback: StoreOnActionListener, detached?: boolean ): () => void + + /** + * Stops the associated effect scope of the store and remove it from the store + * registry. Plugins can override this method to cleanup any added effects. + * e.g. devtools plugin remove its listeners and stops displaying it from + * devtools. + */ + $dispose(): void } /** From 8c50e1968cd9eade95954fd650c27d5ed1eae59e Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 19 Aug 2021 12:45:03 +0200 Subject: [PATCH 2/2] test: fix flush --- packages/pinia/__tests__/store.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pinia/__tests__/store.spec.ts b/packages/pinia/__tests__/store.spec.ts index 705fbe39df..a0c06ff51d 100644 --- a/packages/pinia/__tests__/store.spec.ts +++ b/packages/pinia/__tests__/store.spec.ts @@ -314,7 +314,7 @@ describe('Store', () => { const store = useStore(pinia) const spy = jest.fn() - store.$subscribe(spy) + store.$subscribe(spy, { flush: 'sync' }) pinia.state.value.main.n++ expect(spy).toHaveBeenCalledTimes(1)