From cd268a47f5f0f6e0928ac69958f84ca23168961d Mon Sep 17 00:00:00 2001 From: Andrew Courtice Date: Thu, 5 Aug 2021 14:30:23 +1000 Subject: [PATCH] refactor(core): changed mutation hook name and improved destroyed stores --- core/src/constants.ts | 1 + core/src/index.ts | 2 ++ core/src/store.ts | 58 ++++++++++++++++++++++++------------------- core/src/types.ts | 23 ++++++++++------- 4 files changed, 49 insertions(+), 35 deletions(-) diff --git a/core/src/constants.ts b/core/src/constants.ts index 85d08ba3..c9f58b57 100644 --- a/core/src/constants.ts +++ b/core/src/constants.ts @@ -11,6 +11,7 @@ export const EVENTS = { mutation: { before: 'mutation:before', after: 'mutation:after', + success: 'mutation:success', error: 'mutation:error', }, devtools: { diff --git a/core/src/index.ts b/core/src/index.ts index d8562afa..fc21621c 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -140,6 +140,7 @@ export function createStore(store, extensions); @@ -151,6 +152,7 @@ export function createStore implements InternalSt } public emit(event: string, sender: string, data: any): void { + if (!this.scope.active) { + return; + } + const payload: EventPayload = { data, sender, @@ -124,24 +130,27 @@ export default class Store implements InternalSt return this.scope.run(callback)!; } - public hasRegistration(type: string, name: string): boolean { - return !!this.registrations[type]?.has(name); + public hasRegistration(group: string, name: string): boolean { + return !!this.registrations[group]?.has(name); } - public getRegistration(type: string, name: string): RegistrationValueProducer | undefined { - return this.registrations[type]?.get(name); + public getRegistration(group: string, name: string): StoreRegistration | undefined { + return this.registrations[group]?.get(name); } - public register(type: string, name: string, valueProducer: RegistrationValueProducer): void { - if (!(type in this.registrations)) { - this.registrations[type] = new Map(); + public register(group: string, name: string, producer: RegistrationValueProducer, type: RegistrationType = 'other'): void { + if (!(group in this.registrations)) { + this.registrations[group] = new Map(); } - this.registrations[type].set(name, valueProducer); + this.registrations[group].set(name, { + type, + producer, + }); } - public unregister(type: string, name: string): void { - this.registrations[type]?.delete(name); + public unregister(group: string, name: string): void { + this.registrations[group]?.delete(name); } public getter(name: string, getter: Getter): ComputedRef { @@ -151,22 +160,31 @@ export default class Store implements InternalSt const output = this.track(() => computed(() => getter(this.state))); - this.register('getters', name, () => output.value); + this.register('getters', name, () => output.value, 'computed'); return output; } private mutate(name: string, sender: string, mutator: Mutator, payload: TPayload): TResult { + if (!this.scope.active) { + throw new Error('The current store has been destroyed. Mutations can no longer take place.'); + } + if (this.stack.has(name)) { throw new Error('Circular mutation reference detected. Avoid calling mutations inside other mutations to prevent circular references.'); } + let result: TResult; + const eventData: MutationEventData = { payload, mutation: name, }; - let result: TResult; + const emitComplete = (event: string) => this.emit(event, sender, { + ...eventData, + result, + }); this.stack.add(name); this.emit(EVENTS.mutation.before, sender, eventData); @@ -181,12 +199,10 @@ export default class Store implements InternalSt throw error; } finally { this.stack.delete(name); + emitComplete(EVENTS.mutation.after); } - this.emit(EVENTS.mutation.after, sender, { - ...eventData, - result, - }); + emitComplete(EVENTS.mutation.success); return result; } @@ -205,16 +221,6 @@ export default class Store implements InternalSt return mutation; } - public exec(name: string, payload?: any): TResult { - const mutation = this.getRegistration('mutations', name) as Mutation; - - if (!mutation) { - throw new Error(`No mutation found for ${name}`); - } - - return mutation(payload); - } - public write(name: string, sender: string, mutator: Mutator): TResult { return this.mutate(name, sender, mutator, undefined); } diff --git a/core/src/types.ts b/core/src/types.ts index ce65e11d..5ab2c48f 100644 --- a/core/src/types.ts +++ b/core/src/types.ts @@ -10,6 +10,8 @@ export type BaseState = object; export type StoreProvider = keyof StoreProviders; export type ReadState = DeepReadonly; export type WriteState = TState; +export type RegistrationType = 'ref' | 'reactive' | 'computed' | 'other'; +export type RegistrationValueProducer = () => unknown; export type Getter = (state: ReadState) => TResult; export type Mutator = (state: WriteState, payload: TPayload) => TResult; export type Mutation = undefined extends TPayload ? (payload?: TPayload) => TResult : (payload: TPayload) => TResult; @@ -59,14 +61,13 @@ export interface InternalStore extends StoreBase readonly state: ReadState; name: string; registrations: StoreRegistrations; - hasRegistration(type: string, name: string): boolean; - getRegistration(type: string, name: string): RegistrationValueProducer | undefined; - register(type: string, name: string, valueProducer: RegistrationValueProducer): void; - unregister(type: string, name: string): void; + hasRegistration(group: string, name: string): boolean; + getRegistration(group: string, name: string): StoreRegistration | undefined; + register(group: string, name: string, valueProducer: RegistrationValueProducer, type?: RegistrationType): void; + unregister(group: string, name: string): void; emit(event: string, sender: string, data: any): void; on(event: string, handler: EventHandler): EventListener; once(event: string, handler: EventHandler): EventListener - exec(name: string, payload?: any): TResult; track(callback: () => TResult): TResult; provider>(key: TKey, value: StoreProviders[TKey]): void; write(name: string, sender: string, mutator: Mutator): TResult; @@ -89,6 +90,7 @@ export interface Store extends StoreBase { destroy(): void; onBeforeMutation(mutationName: string | string[], handler: MutationHookHandler): EventListener; onAfterMutation(mutationName: string | string[], handler: MutationHookHandler): EventListener; + onMutationSuccess(mutationName: string | string[], handler: MutationHookHandler): EventListener; onMutationError(mutationName: string | string[], handler: MutationHookHandler): EventListener; } @@ -101,10 +103,13 @@ export interface PluginOptions { plugins?: HarlemPlugin[]; } -export type RegistrationValueProducer = () => unknown; +export interface StoreRegistration { + type: RegistrationType; + producer: RegistrationValueProducer; +} export interface StoreRegistrations { - [key: string]: Map; - getters: Map; - mutations: Map; + [key: string]: Map; + getters: Map; + mutations: Map; }