]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
fix(patch): avoid merging reactive objects
authorEduardo San Martin Morote <posva13@gmail.com>
Mon, 7 Jun 2021 21:16:52 +0000 (23:16 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Mon, 7 Jun 2021 21:20:38 +0000 (23:20 +0200)
Fix #528

__tests__/store.patch.spec.ts
src/store.ts

index 8013c008cb2f9b7ac84df8fea1d6a9cd72ae2bf0..f877bf4294735266d92a33694d49032d1dd6acf5 100644 (file)
@@ -1,4 +1,5 @@
-import { defineStore, setActivePinia, createPinia, Pinia } from '../src'
+import { reactive, ref } from '@vue/composition-api'
+import { createPinia, defineStore, setActivePinia, Pinia } from '../src'
 
 describe('store.patch', () => {
   let pinia: Pinia
@@ -84,4 +85,55 @@ describe('store.patch', () => {
       list: [],
     })
   })
+
+  describe('skipping nested objects', () => {
+    const useStore = () => {
+      // create a new store
+      setActivePinia(createPinia())
+      return defineStore({
+        id: 'main',
+        state: () => ({
+          arr: [] as any[],
+          item: { a: 0, b: 0 } as null | { a: number; b?: number },
+        }),
+      })()
+    }
+
+    it('ref', () => {
+      const store = useStore()
+      const item = ref({ a: 1, b: 1 })
+      const oldItem = store.item
+      // @ts-expect-error: because it's a ref
+      store.$patch({ item })
+      expect(oldItem).toEqual({ a: 0, b: 0 })
+      expect(store.item).toEqual({ a: 1, b: 1 })
+    })
+
+    it('nested ref', () => {
+      const store = useStore()
+      const item = ref({ nested: { a: 1, b: 1 } })
+      const oldItem = store.item
+      store.$patch({ item: item.value.nested })
+      expect(oldItem).toEqual({ a: 0, b: 0 })
+      expect(store.item).toEqual({ a: 1, b: 1 })
+    })
+
+    it('reactive', () => {
+      const store = useStore()
+      const item = reactive({ a: 1, b: 1 })
+      const oldItem = store.item
+      store.$patch({ item })
+      expect(oldItem).toEqual({ a: 0, b: 0 })
+      expect(store.item).toEqual({ a: 1, b: 1 })
+    })
+
+    it('from store', () => {
+      const store = useStore()
+      store.arr.push({ a: 1, b: 1 })
+      const oldItem = store.item
+      store.$patch({ item: store.arr[0] })
+      expect(oldItem).toEqual({ a: 0, b: 0 })
+      expect(store.item).toEqual({ a: 1, b: 1 })
+    })
+  })
 })
index e4f9927f705a72efd242469246afcd7eaacb5ce6..5e44cffcc9a79d31dd4b148e8dfea3ede8d0c351 100644 (file)
@@ -11,6 +11,8 @@ import {
   provide,
   UnwrapRef,
   set,
+  isRef,
+  isReactive,
 } from '@vue/composition-api'
 import {
   StateTree,
@@ -50,7 +52,12 @@ function innerPatch<T extends StateTree>(
   for (const key in patchToApply) {
     const subPatch = patchToApply[key]
     const targetValue = target[key]
-    if (isPlainObject(targetValue) && isPlainObject(subPatch)) {
+    if (
+      isPlainObject(targetValue) &&
+      isPlainObject(subPatch) &&
+      !isRef(subPatch) &&
+      !isReactive(subPatch)
+    ) {
       target[key] = innerPatch(targetValue, subPatch)
     } else {
       // @ts-expect-error