]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
fix: allow `$reset` to be overridden by plugins (#2054)
authorEduardo San Martin Morote <posva@users.noreply.github.com>
Mon, 6 Mar 2023 09:20:03 +0000 (10:20 +0100)
committerGitHub <noreply@github.com>
Mon, 6 Mar 2023 09:20:03 +0000 (10:20 +0100)
Co-authored-by: Cygnut <ligand@hotmail.co.uk>
packages/docs/core-concepts/plugins.md
packages/pinia/__tests__/storePlugins.spec.ts
packages/pinia/src/store.ts

index 2048ef7d4280c7519ffe1a1d543dd2ff573aa18c..ab028d22a8a6df6dd2b182dee80e1a5ce3437976 100644 (file)
@@ -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:
index d589a5b08ecac90af83eb6807e03b9f3c5913b70..17f73983c467ceb8f33675e8345c88f643d46c8e 100644 (file)
@@ -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()
 
index 7a7356a482fa8b20f2453e4fd1a33caa922e7514..0c77d2e59c15ef54696c6e3de5c46ba3d6937762 100644 (file)
@@ -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<Id, S, G, A>) {
+        const { state } = options as DefineStoreOptions<Id, S, G, A>
+        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().`