]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat(ssr): add skipHydrate to skip hydration on specific refs
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 25 Oct 2021 14:36:26 +0000 (16:36 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 25 Oct 2021 14:36:26 +0000 (16:36 +0200)
packages/pinia/__tests__/state.spec.ts
packages/pinia/src/index.ts
packages/pinia/src/store.ts

index 42be6ab908b430d11e748025984d6d36b0d8a599..a72140fb31c9f7ba2d77ac3a53fe81cfd6d61bf5 100644 (file)
@@ -1,5 +1,5 @@
-import { createPinia, defineStore, setActivePinia } from '../src'
-import { computed, nextTick, reactive, ref, watch } from 'vue'
+import { createPinia, defineStore, setActivePinia, skipHydrate } from '../src'
+import { computed, nextTick, reactive, ref, watch, customRef } from 'vue'
 
 describe('State', () => {
   beforeEach(() => {
@@ -288,4 +288,50 @@ describe('State', () => {
     expect(store.$state.stuff).toBe(15)
     expect(store.double).toBe(30)
   })
+
+  describe('custom refs', () => {
+    let spy!: jest.SpyInstance
+    function useCustomRef() {
+      let value = 0
+
+      return customRef((track, trigger) => {
+        spy = jest.fn(function (newValue: number) {
+          value = newValue
+          trigger()
+        })
+        return {
+          get() {
+            track()
+            return value
+          },
+          set: spy as any,
+        }
+      })
+    }
+
+    it('hydrates custom refs setup', async () => {
+      const pinia = createPinia()
+      pinia.state.value.main = { myCustom: 24 }
+
+      setActivePinia(pinia)
+
+      const useMainOptions = defineStore('main', () => ({
+        myCustom: skipHydrate(useCustomRef()),
+      }))
+
+      const main = useMainOptions()
+
+      // 0 because it skipped hydration
+      expect(main.myCustom).toBe(0)
+      expect(spy).toHaveBeenCalledTimes(0)
+      main.myCustom++
+      main.$state.myCustom++
+      main.$patch({ myCustom: 0 })
+      main.$patch((state) => {
+        state.myCustom++
+      })
+      expect(main.myCustom).toBe(1)
+      expect(spy).toHaveBeenCalledTimes(4)
+    })
+  })
 })
index f46c3d0ccd3320f6526b645e51f80d0352d95554..dd52d97ecdb43e97bed32976c6a09473d27c80f4 100644 (file)
@@ -5,7 +5,7 @@ export { setActivePinia, getActivePinia } from './rootStore'
 export { createPinia } from './createPinia'
 export type { Pinia, PiniaStorePlugin, PiniaPluginContext } from './rootStore'
 
-export { defineStore } from './store'
+export { defineStore, skipHydrate } from './store'
 export type { StoreActions, StoreGetters, StoreState } from './store'
 
 export type {
index f4a037b1a15b5078163c29e0e1abe76ca81b37dc..d30301fc2824d0460f7d9c8f819f4c435c659431 100644 (file)
@@ -73,6 +73,16 @@ function innerPatch<T extends StateTree>(
   return target
 }
 
+const skipHydrateSymbol = __DEV__ ? Symbol('pinia:skipHydration') : Symbol()
+
+export function skipHydrate<T = any>(obj: T): T {
+  return Object.defineProperty(obj, skipHydrateSymbol, {})
+}
+
+function shouldHydrate(obj: any) {
+  return !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol)
+}
+
 const { assign } = Object
 
 function isComputed<T>(value: ComputedRef<T> | unknown): value is ComputedRef<T>
@@ -445,7 +455,7 @@ function createSetupStore<
         // can just skip that
       } else if (!buildState) {
         // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created
-        if (initialState) {
+        if (initialState && shouldHydrate(prop)) {
           if (isRef(prop)) {
             prop.value = initialState[key]
           } else {