]> 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:16:52 +0000 (23:16 +0200)
Fix #528

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

index 6b6c1f8e4d045553db740f4570c31e89ac97bae9..9156f5439ed75dceb679198edc9b65cb92c9a00d 100644 (file)
@@ -1,3 +1,4 @@
+import { reactive, ref } from 'vue'
 import { createPinia, defineStore, setActivePinia } from '../src'
 
 describe('store.$patch', () => {
@@ -81,4 +82,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 105d11211ca706f11cdecbe61ad4f56ccc947799..0a7964c24e2986317d31018f6b3a1b1ee67cef0f 100644 (file)
@@ -12,6 +12,8 @@ import {
   WatchOptions,
   UnwrapRef,
   markRaw,
+  isRef,
+  isReactive,
 } from 'vue'
 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-ignore