From a579fb0a87816626ab390367c2d71e189771699c Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Sat, 23 Nov 2019 13:05:53 +0100 Subject: [PATCH] refactor: use id instead of name --- src/devtools.ts | 14 +++++++------- src/index.ts | 47 ++++++++++++++++++++++++++++++++++++++++------- src/types.ts | 27 ++++++++++++++++++++++++--- src/useStore.ts | 0 4 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 src/useStore.ts diff --git a/src/devtools.ts b/src/devtools.ts index 926239d7..d2b92347 100644 --- a/src/devtools.ts +++ b/src/devtools.ts @@ -29,7 +29,7 @@ interface RootState { let rootStore: RootState -export function devtoolPlugin(store: Store) { +export function devtoolPlugin(store: Store) { if (!devtoolHook) return if (!rootStore) { @@ -57,26 +57,26 @@ export function devtoolPlugin(store: Store) { devtoolHook.emit('vuex:init', rootStore) } - rootStore.state[store.name] = store.state + rootStore.state[store.id] = store.state // tell the devtools we added a module - rootStore.registerModule(store.name, store) + rootStore.registerModule(store.id, store) - Object.defineProperty(rootStore.state, store.name, { + Object.defineProperty(rootStore.state, store.id, { get: () => store.state, set: state => store.replaceState(state), }) // Vue.set(rootStore.state, store.name, store.state) // the trailing slash is removed by the devtools - rootStore._modulesNamespaceMap[store.name + '/'] = true + rootStore._modulesNamespaceMap[store.id + '/'] = true devtoolHook.on('vuex:travel-to-state', targetState => { - store.replaceState(targetState[store.name] as S) + store.replaceState(targetState[store.id]) }) store.subscribe((mutation, state) => { - rootStore.state[store.name] = state + rootStore.state[store.id] = state devtoolHook.emit( 'vuex:mutation', { diff --git a/src/index.ts b/src/index.ts index a23671fe..bca3d75b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -43,11 +43,22 @@ function innerPatch( return target } -export function createStore( - name: string, +/** + * NOTE: by allowing users to name stores correctly, they can nest them the way + * they want, no? like user/cart + */ + +/** + * Creates a store instance + * @param id unique identifier of the store, like a name. eg: main, cart, user + * @param initialState initial state applied to the store, Must be correctly typed to infer typings + */ + +export function createStore( + id: Id, initialState: S // methods: Record -): Store { +): Store { const { state, replaceState } = createState(initialState) let isListening = true @@ -58,7 +69,7 @@ export function createStore( state => { if (isListening) { subscriptions.forEach(callback => { - callback({ storeName: name, type: '🧩 in place', payload: {} }, state) + callback({ storeName: id, type: '🧩 in place', payload: {} }, state) }) } }, @@ -74,7 +85,7 @@ export function createStore( isListening = true subscriptions.forEach(callback => { callback( - { storeName: name, type: '⤵️ patch', payload: partialState }, + { storeName: id, type: '⤵️ patch', payload: partialState }, state.value ) }) @@ -85,8 +96,8 @@ export function createStore( // TODO: return function to remove subscription } - const store: Store = { - name, + const store: Store = { + id, // it is replaced below by a getter state: state.value, @@ -110,6 +121,28 @@ export function createStore( return store } +function makeStore( + id: Id, + initialState: S +) { + let store: Store | undefined + + function useStore(): Store { + if (!store) store = createStore(id, initialState) + + return store + } + + function clear(): void { + store = undefined + } + + return { + useStore, + clear, + } +} + // export const store = createStore('main', initialState) // export const cartStore = createStore('cart', { // items: ['thing 1'], diff --git a/src/types.ts b/src/types.ts index ff717369..76cce8eb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -50,18 +50,39 @@ export type SubscriptionCallback = ( state: S ) => void -export interface Store { - name: string +export interface Store { + /** + * Unique identifier of the store + */ + id: Id + /** + * State of the Store + */ state: S + /** + * Applies a state patch to current state. Allows passing nested values + * @param partialState patch to apply to the state + */ patch(partialState: DeepPartial): void + /** + * Replaces current state with a completely new version. + * @param newState state object to replace current state + */ replaceState(newState: S): void + /** + * Setups a callback to be called whenever the state changes. + * @param callback callback that is called whenever the state changes + */ subscribe(callback: SubscriptionCallback): void } export interface DevtoolHook { - on(event: string, callback: (targetState: StateTree) => void): void + on( + event: string, + callback: (targetState: Record) => void + ): void // eslint-disable-next-line @typescript-eslint/no-explicit-any emit(event: string, ...payload: any[]): void } diff --git a/src/useStore.ts b/src/useStore.ts new file mode 100644 index 00000000..e69de29b -- 2.47.2