]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
fix(ssr): properly hydrate setup stores
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 27 Aug 2021 16:34:58 +0000 (18:34 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Fri, 27 Aug 2021 16:34:58 +0000 (18:34 +0200)
packages/pinia/__tests__/state.spec.ts
packages/pinia/src/store.ts

index 119b2d83bbf3626cb5d15b79d1e00501c6f57218..42be6ab908b430d11e748025984d6d36b0d8a599 100644 (file)
@@ -1,5 +1,5 @@
 import { createPinia, defineStore, setActivePinia } from '../src'
-import { computed, nextTick, ref, watch } from 'vue'
+import { computed, nextTick, reactive, ref, watch } from 'vue'
 
 describe('State', () => {
   beforeEach(() => {
@@ -213,4 +213,79 @@ describe('State', () => {
     store.$reset()
     expect(store.$state).toEqual({})
   })
+
+  it('can hydrate refs', () => {
+    const pinia = createPinia()
+    setActivePinia(pinia)
+    pinia.state.value.main = {
+      stuff: 1,
+      a: 2,
+      // nested: { a: 2 },
+      state: {
+        count: 5,
+        a: 2,
+        // nested: { a: 2 },
+      },
+    }
+
+    const stuff = ref(2)
+    const useStore = defineStore('main', () => {
+      const a = ref(0)
+      // const nested = ref({ a })
+      const state = reactive({
+        a,
+        // nested,
+        count: 0,
+      })
+      return {
+        stuff,
+        a,
+        // nested,
+        state,
+        double: computed(() => stuff.value * 2),
+      }
+    })
+
+    const store = useStore()
+
+    expect(stuff.value).toBe(1)
+    expect(store.$state).toEqual({
+      stuff: 1,
+      a: 2,
+      // nested: { a: 2 },
+      state: {
+        // nested: { a: 2 },
+        count: 5,
+        a: 2,
+      },
+    })
+    expect(store.stuff).toBe(1)
+    expect(store.double).toBe(2)
+    expect(store.a).toBe(2)
+    expect(store.state).toEqual({
+      // nested: { a: 2 },
+      a: 2,
+      count: 5,
+    })
+
+    store.a = 0
+    expect(store.a).toBe(0)
+    expect(store.state).toEqual({
+      // nested: { a: 0 },
+      a: 0,
+      count: 5,
+    })
+
+    store.stuff = 5
+    expect(store.stuff).toBe(5)
+    expect(stuff.value).toBe(5)
+    expect(store.$state.stuff).toBe(5)
+    expect(store.double).toBe(10)
+
+    stuff.value = 15
+    expect(store.stuff).toBe(15)
+    expect(stuff.value).toBe(15)
+    expect(store.$state.stuff).toBe(15)
+    expect(store.double).toBe(30)
+  })
 })
index 4d9df150ebf510cfad56090d8ec77db5ea9dc3e4..94c50471da4404fd53b8e2fab0894f93f108003f 100644 (file)
@@ -66,7 +66,7 @@ function innerPatch<T extends StateTree>(
     ) {
       target[key] = innerPatch(targetValue, subPatch)
     } else {
-      // @ts-ignore
+      // @ts-expect-error: subPatch is a valid value
       target[key] = subPatch
     }
   }
@@ -431,12 +431,21 @@ function createSetupStore<
         // createOptionStore directly sets the state in pinia.state.value so we
         // can just skip that
       } else if (!buildState) {
+        // we must hydrate the state
+        if (initialState) {
+          if (isRef(prop)) {
+            prop.value = initialState[key]
+          } else {
+            // probably a reactive object, lets recursively assign
+            innerPatch(prop, initialState[key])
+          }
+        }
+        // transfer the ref to the pinia state to keep everything in sync
         if (isVue2) {
           set(pinia.state.value[$id], key, prop)
         } else {
           pinia.state.value[$id][key] = prop
         }
-        // TODO: avoid if state exists for SSR
       }
 
       /* istanbul ignore else */