]> git.ipfire.org Git - thirdparty/vuejs/pinia.git/commitdiff
feat: allow passing a function to $patch
authorEduardo San Martin Morote <posva13@gmail.com>
Thu, 1 Apr 2021 14:37:20 +0000 (16:37 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Thu, 1 Apr 2021 14:39:28 +0000 (16:39 +0200)
__tests__/store.patch.spec.ts
src/store.ts
src/types.ts

index ffe2e2bb44e1298e536927092d57ac36351f881e..2325826af781fef8be9c0ac5de6958b2a5944322 100644 (file)
@@ -17,6 +17,7 @@ describe('store.patch', () => {
           foo: 'foo',
           a: { b: 'string' },
         },
+        list: [] as number[],
       }),
     })()
   }
@@ -30,6 +31,24 @@ describe('store.patch', () => {
         foo: 'foo',
         a: { b: 'string' },
       },
+      list: [],
+    })
+  })
+
+  it('patches using a function', () => {
+    const store = useStore()
+    store.$patch((state) => {
+      expect(state).toBe(store.$state)
+      state.a = !state.a
+      state.list.push(1)
+    })
+    expect(store.$state).toEqual({
+      a: false,
+      nested: {
+        foo: 'foo',
+        a: { b: 'string' },
+      },
+      list: [1],
     })
   })
 
@@ -42,6 +61,7 @@ describe('store.patch', () => {
         foo: 'bar',
         a: { b: 'string' },
       },
+      list: [],
     })
     store.$patch({ nested: { a: { b: 'hello' } } })
     expect(store.$state).toEqual({
@@ -50,6 +70,7 @@ describe('store.patch', () => {
         foo: 'bar',
         a: { b: 'hello' },
       },
+      list: [],
     })
   })
 
@@ -62,6 +83,7 @@ describe('store.patch', () => {
         foo: 'hello',
         a: { b: 'string' },
       },
+      list: [],
     })
   })
 })
index 61c4aeefcc6b82a62a8a527313c4e1861a0e2cc1..8eff1e268cc778349b378f7b4ef7a6b1cb3d91d2 100644 (file)
@@ -96,14 +96,27 @@ function initStore<Id extends string, S extends StateTree>(
   let isListening = true
   let subscriptions: SubscriptionCallback<S>[] = []
 
-  function $patch(partialState: DeepPartial<S>): void {
+  function $patch(stateMutation: (state: S) => void): void
+  function $patch(partialState: DeepPartial<S>): void
+  function $patch(
+    partialStateOrMutator: DeepPartial<S> | ((state: S) => void)
+  ): void {
+    let partialState: DeepPartial<S> = {}
+    let type: string
     isListening = false
-    innerPatch(pinia.state.value[$id], partialState)
+    if (typeof partialStateOrMutator === 'function') {
+      partialStateOrMutator(pinia.state.value[$id])
+      type = '🧩 patch'
+    } else {
+      innerPatch(pinia.state.value[$id], partialStateOrMutator)
+      partialState = partialStateOrMutator
+      type = '⤵️ patch'
+    }
     isListening = true
     // because we paused the watcher, we need to manually call the subscriptions
     subscriptions.forEach((callback) => {
       callback(
-        { storeName: $id, type: '⤵️ patch', payload: partialState },
+        { storeName: $id, type, payload: partialState },
         pinia.state.value[$id]
       )
     })
index b707f1939dfcb41d567ac1cb74ff649ec83b83ad..3c774617b9892adae7f16cb279d3a5295da8c8b7 100644 (file)
@@ -56,6 +56,15 @@ export interface StoreWithState<Id extends string, S extends StateTree> {
    */
   $patch(partialState: DeepPartial<S>): void
 
+  /**
+   * Group multiple changes into one function. Useful when mutating objects like
+   * Sets or arrays and applying an object patch isn't practical, e.g. appending
+   * to an array.
+   *
+   * @param stateMutator - function that mutates `state`
+   */
+  $patch(stateMutator: (state: S) => void): void
+
   /**
    * Resets the store to its initial state by removing all subscriptions and
    * building a new state object