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

index 4469a45b325d018b2fec5a7742a1fffc0fa3d8a7..274f34f774f851b51201a135e78d70a59674d517 100644 (file)
@@ -12,6 +12,7 @@ describe('store.$patch', () => {
           foo: 'foo',
           a: { b: 'string' },
         },
+        list: [] as number[],
       }),
     })()
   }
@@ -25,6 +26,23 @@ describe('store.$patch', () => {
         foo: 'foo',
         a: { b: 'string' },
       },
+      list: [],
+    })
+  })
+
+  it('patches using a function', () => {
+    const store = useStore()
+    store.$patch((state) => {
+      state.a = !state.a
+      state.list.push(1)
+    })
+    expect(store.$state).toEqual({
+      a: false,
+      nested: {
+        foo: 'foo',
+        a: { b: 'string' },
+      },
+      list: [1],
     })
   })
 
@@ -37,6 +55,7 @@ describe('store.$patch', () => {
         foo: 'bar',
         a: { b: 'string' },
       },
+      list: [],
     })
     store.$patch({ nested: { a: { b: 'hello' } } })
     expect(store.$state).toEqual({
@@ -45,6 +64,7 @@ describe('store.$patch', () => {
         foo: 'bar',
         a: { b: 'hello' },
       },
+      list: [],
     })
   })
 
@@ -57,6 +77,7 @@ describe('store.$patch', () => {
         foo: 'hello',
         a: { b: 'string' },
       },
+      list: [],
     })
   })
 })
index bbc83308af44fe3425528e9a3cd8c386fecd77b9..792168e247b61b9aa5e9edf7c3f26c6288021f5b 100644 (file)
@@ -89,14 +89,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 d58de224e5db2dffb25b5f71edddb36f3f35caaa..543f8792525f8e9b619a4f161539f602771c4b80 100644 (file)
@@ -71,6 +71,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