From: Eduardo San Martin Morote Date: Mon, 6 Mar 2023 09:20:03 +0000 (+0100) Subject: fix: allow `$reset` to be overridden by plugins (#2054) X-Git-Tag: pinia@2.0.33~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=709e2b1a77410331ee1ce88212ac55a4e92fa941;p=thirdparty%2Fvuejs%2Fpinia.git fix: allow `$reset` to be overridden by plugins (#2054) Co-authored-by: Cygnut --- diff --git a/packages/docs/core-concepts/plugins.md b/packages/docs/core-concepts/plugins.md index 2048ef7d..ab028d22 100644 --- a/packages/docs/core-concepts/plugins.md +++ b/packages/docs/core-concepts/plugins.md @@ -144,7 +144,7 @@ If you are using **Vue 2**, Pinia is subject to the [same reactivity caveats](ht ```js import { set, toRef } from '@vue/composition-api' pinia.use(({ store }) => { - if (!Object.prototype.hasOwnProperty(store.$state, 'hello')) { + if (!Object.prototype.hasOwnProperty(store.$state, 'secret')) { const secretRef = ref('secret') // If the data is meant to be used during SSR, you should // set it on the `$state` property so it is serialized and @@ -160,6 +160,34 @@ pinia.use(({ store }) => { ::: +#### Resetting state added in plugins + +By default, `$reset()` will not reset state added by plugins but you can override it to also reset the state you add: + +```js +import { toRef, ref } from 'vue' + +pinia.use(({ store }) => { + // this is the same code as above for reference + if (!Object.prototype.hasOwnProperty(store.$state, 'hasError')) { + const hasError = ref(false) + store.$state.hasError = hasError + } + store.hasError = toRef(store.$state, 'hasError') + + // make sure to set the context (`this`) to the store + const originalReset = store.$reset.bind(store) + + // override the $reset function + return { + $reset() { + originalReset() + store.hasError = false + } + } +}) +``` + ## Adding new external properties When adding external properties, class instances that come from other libraries, or simply things that are not reactive, you should wrap the object with `markRaw()` before passing it to pinia. Here is an example adding the router to every store: diff --git a/packages/pinia/__tests__/storePlugins.spec.ts b/packages/pinia/__tests__/storePlugins.spec.ts index d589a5b0..17f73983 100644 --- a/packages/pinia/__tests__/storePlugins.spec.ts +++ b/packages/pinia/__tests__/storePlugins.spec.ts @@ -23,9 +23,7 @@ declare module '../src' { } describe('store plugins', () => { - const useStore = defineStore({ - id: 'test', - + const useStore = defineStore('test', { actions: { incrementN() { return this.pluginN++ @@ -64,6 +62,41 @@ describe('store plugins', () => { store.idFromPlugin == 'hello' }) + it('overrides $reset', () => { + const pinia = createPinia() + + const useStore = defineStore('main', { + state: () => ({ n: 0 }), + }) + + mount({ template: 'none' }, { global: { plugins: [pinia] } }) + + pinia.use(({ app, store }) => { + if (!store.$state.hasOwnProperty('pluginN')) { + // @ts-expect-error: cannot be a ref yet + store.$state.pluginN = ref(20) + } + // @ts-expect-error: TODO: allow setting refs + store.pluginN = toRef(store.$state, 'pluginN') + + const originalReset = store.$reset.bind(store) + return { + uid: app._uid, + $reset() { + originalReset() + store.pluginN = 20 + }, + } + }) + + const store = useStore(pinia) + + store.pluginN = 200 + store.$reset() + expect(store.$state.pluginN).toBe(20) + expect(store.pluginN).toBe(20) + }) + it('can install plugins before installing pinia', () => { const pinia = createPinia() diff --git a/packages/pinia/src/store.ts b/packages/pinia/src/store.ts index 7a7356a4..0c77d2e5 100644 --- a/packages/pinia/src/store.ts +++ b/packages/pinia/src/store.ts @@ -195,14 +195,6 @@ function createOptionsStore< store = createSetupStore(id, setup, options, pinia, hot, true) - store.$reset = function $reset() { - const newState = state ? state() : {} - // we use a patch to group all changes into one single subscription - this.$patch(($state) => { - assign($state, newState) - }) - } - return store as any } @@ -329,8 +321,17 @@ function createSetupStore< ) } - /* istanbul ignore next */ - const $reset = __DEV__ + const $reset = isOptionsStore + ? function $reset(this: _StoreWithState) { + const { state } = options as DefineStoreOptions + const newState = state ? state() : {} + // we use a patch to group all changes into one single subscription + this.$patch(($state) => { + assign($state, newState) + }) + } + : /* istanbul ignore next */ + __DEV__ ? () => { throw new Error( `🍍: Store "${$id}" is built using the setup syntax and does not implement $reset().`