-import {
- createPinia,
- defineStore,
- setActivePinia,
- Pinia,
- MutationType,
-} from '../src'
+import { createPinia, defineStore, setActivePinia, Pinia } from '../src'
import { mount } from '@vue/test-utils'
import { defineComponent, getCurrentInstance, nextTick, watch } from 'vue'
expect(store2.$state.nested.a.b).toBe('string')
})
- it('subscribe to changes', () => {
- const store = useStore()
- const spy = jest.fn()
- store.$subscribe(spy)
-
- store.$state.a = false
-
- expect(spy).toHaveBeenCalledWith(
- expect.objectContaining({
- payload: {},
- storeName: 'main',
- type: MutationType.direct,
- }),
- store.$state
- )
- })
-
- it('subscribe to changes done via patch', () => {
- const store = useStore()
- const spy = jest.fn()
- store.$subscribe(spy)
-
- const patch = { a: false }
- store.$patch(patch)
-
- expect(spy).toHaveBeenCalledWith(
- expect.objectContaining({
- payload: patch,
- storeName: 'main',
- type: MutationType.patchObject,
- }),
- store.$state
- )
- })
-
it('should outlive components', async () => {
const pinia = createPinia()
const useStore = defineStore({
-import { createPinia, defineStore, setActivePinia } from '../src'
+import { createPinia, defineStore, MutationType, setActivePinia } from '../src'
import { mount } from '@vue/test-utils'
describe('Subscriptions', () => {
store.$subscribe(spy)
store.$state.name = 'Cleiton'
expect(spy).toHaveBeenCalledTimes(1)
+ expect(spy).toHaveBeenCalledWith(
+ expect.objectContaining({
+ storeName: 'main',
+ storeId: 'main',
+ type: MutationType.direct,
+ }),
+ store.$state
+ )
+ })
+
+ it('subscribe to changes done via patch', () => {
+ const store = useStore()
+ const spy = jest.fn()
+ store.$subscribe(spy)
+
+ const patch = { name: 'Cleiton' }
+ store.$patch(patch)
+
+ expect(spy).toHaveBeenCalledWith(
+ expect.objectContaining({
+ payload: patch,
+ storeName: 'main',
+ storeId: 'main',
+ type: MutationType.patchObject,
+ }),
+ store.$state
+ )
})
it('unsubscribes callback when unsubscribe is called', () => {
StoreWithState,
StoreOnActionListener,
StoreOnActionListenerContext,
+ SubscriptionCallback,
PiniaCustomProperties,
DefineStoreOptions,
} from './types'
StoreOnActionListener,
UnwrapPromise,
ActionsTree,
+ SubscriptionCallbackMutation,
} from './types'
import {
getActivePinia,
function $patch(
partialStateOrMutator: DeepPartial<S> | ((state: S) => void)
): void {
- let partialState: DeepPartial<S> = {}
- let type: MutationType
+ let subscriptionMutation: SubscriptionCallbackMutation<S>
isListening = false
// reset the debugger events since patches are sync
/* istanbul ignore else */
}
if (typeof partialStateOrMutator === 'function') {
partialStateOrMutator(pinia.state.value[$id])
- type = MutationType.patchFunction
+ subscriptionMutation = {
+ type: MutationType.patchFunction,
+ storeName: $id,
+ storeId: $id,
+ events: debuggerEvents as DebuggerEvent[],
+ }
} else {
innerPatch(pinia.state.value[$id], partialStateOrMutator)
- partialState = partialStateOrMutator
- type = MutationType.patchObject
+ subscriptionMutation = {
+ type: MutationType.patchObject,
+ payload: partialStateOrMutator,
+ storeName: $id,
+ storeId: $id,
+ events: debuggerEvents as DebuggerEvent[],
+ }
}
isListening = true
// because we paused the watcher, we need to manually call the subscriptions
subscriptions.forEach((callback) => {
- callback(
- { storeName: $id, type, payload: partialState, events: debuggerEvents },
- pinia.state.value[$id] as UnwrapRef<S>
- )
+ callback(subscriptionMutation, pinia.state.value[$id] as UnwrapRef<S>)
})
}
callback(
{
storeName: $id,
+ storeId: $id,
type: MutationType.direct,
- payload: {},
- events: debuggerEvents,
+ events: debuggerEvents as DebuggerEvent,
},
state
)
// maybe reset? for $state = {} and $reset
}
+/**
+ * Base type for the context passed to a subscription callback.
+ *
+ * @internal
+ */
+export interface _SubscriptionCallbackMutationBase {
+ /**
+ * Type of the mutation.
+ */
+ type: MutationType
+
+ /**
+ * @deprecated use `storeId` instead.
+ */
+ storeName: string
+
+ /**
+ * `id` of the store doing the mutation.
+ */
+ storeId: string
+}
+
+/**
+ * Context passed to a subscription callback when directly mutating the state of
+ * a store with `store.someState = newValue` or `store.$state.someState =
+ * newValue`.
+ */
+export interface SubscriptionCallbackMutationDirect
+ extends _SubscriptionCallbackMutationBase {
+ type: MutationType.direct
+
+ /**
+ * DEV ONLY. Different mutation calls.
+ */
+ events: DebuggerEvent
+}
+
+/**
+ * Context passed to a subscription callback when `store.$patch()` is called
+ * with an object.
+ */
+export interface SubscriptionCallbackMutationPatchObject<S>
+ extends _SubscriptionCallbackMutationBase {
+ type: MutationType.patchObject
+
+ /**
+ * DEV ONLY. Array for patch calls.
+ */
+ events: DebuggerEvent[]
+
+ /**
+ * Object passed to `store.$patch()`.
+ */
+ payload: DeepPartial<S>
+}
+
+/**
+ * Context passed to a subscription callback when `store.$patch()` is called
+ * with a function.
+ */
+export interface SubscriptionCallbackMutationPatchFunction
+ extends _SubscriptionCallbackMutationBase {
+ type: MutationType.patchFunction
+
+ /**
+ * DEV ONLY. Array of all the mutations done inside of the callback.
+ */
+ events: DebuggerEvent[]
+
+ /**
+ * Object passed to `store.$patch()`.
+ */
+ // payload: DeepPartial<UnwrapRef<S>>
+}
+
+/**
+ * Context object passed to a subscription callback.
+ */
+export type SubscriptionCallbackMutation<S> =
+ | SubscriptionCallbackMutationDirect
+ | SubscriptionCallbackMutationPatchObject<S>
+ | SubscriptionCallbackMutationPatchFunction
+
export type UnwrapPromise<T> = T extends Promise<infer V> ? V : T
+/**
+ * Callback of a subscription
+ */
+export type SubscriptionCallback<S> = (
+ /**
+ * Object with information relative to the store mutation that triggered the
+ * subscription.
+ */
+ mutation: SubscriptionCallbackMutation<S>,
+
+ /**
+ * State of the store when the subscription is triggered. Same as
+ * `store.$state`.
+ */
+ state: UnwrapRef<S>
+) => void
+
/**
* Context object passed to callbacks of `store.$onAction(context => {})`
*/
A /* extends ActionsTree */
> = (context: StoreOnActionListenerContext<Id, S, G, A>) => void
-/**
- * Callback of a subscription
- */
-export type SubscriptionCallback<S> = (
- // TODO: make type an enumeration
- // TODO: payload should be optional
- mutation: {
- storeName: string
- type: MutationType
-
- /**
- * DEV ONLY. Array for patch calls and single values for direct edits
- */
- events?: DebuggerEvent[] | DebuggerEvent
-
- payload: DeepPartial<UnwrapRef<S>>
- },
- state: UnwrapRef<S>
-) => void
-
/**
* Base store with state and functions
* @internal
* cleanup up when the component gets unmounted.
*
* @param callback - callback passed to the watcher
- * @param onTrigger - DEV ONLY watcher debugging
- * (https://v3.vuejs.org/guide/reactivity-computed-watchers.html#watcher-debugging)
* @returns function that removes the watcher
*/
- $subscribe(
- callback: SubscriptionCallback<S>,
- onTrigger?: (event: DebuggerEvent) => void
- ): () => void
+ $subscribe(callback: SubscriptionCallback<S>): () => void
/**
* Array of registered action subscriptions.