Last active
January 7, 2024 01:10
-
-
Save hendrysadrak/af379c8eeaa9ba377b8be809e1381a80 to your computer and use it in GitHub Desktop.
Vue 2.7, Composition API, Vuex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { store, type RootState } from '@/store' | |
import { mapValues } from 'lodash' | |
import { computed, getCurrentInstance, type ComputedRef } from 'vue' | |
import type { ActionTree, GetterTree, MutationTree, Store } from 'vuex' | |
type GetRestParams<T extends (a: any, ...args: any) => any> = T extends ( | |
a: any, | |
...args: infer P | |
) => any | |
? P | |
: never | |
export const useRootStore = (): Store<RootState> => { | |
const $root = getCurrentInstance()!.proxy.$root | |
return $root.$store as Store<RootState> | |
} | |
type GenericModule = { | |
state: Record<string, unknown> | |
getters: GetterTree<any, any> | |
actions: ActionTree<any, any> | |
name: string | |
} | |
type GenericStore = Store<any> | |
const _getActions = < | |
Module extends GenericModule, | |
Actions = Module['actions'], | |
ActionsMapped = { | |
[Name in keyof Actions]: ( | |
...args: GetRestParams<Actions[Name]> | |
) => Promise<Awaited<ReturnType<Actions[Name]>>> | |
}, | |
>( | |
{ actions }: GenericModule, | |
store: GenericStore, | |
namespace: string, | |
): ActionsMapped => | |
mapValues( | |
actions, | |
(_, name) => | |
async (...args: any[]) => | |
await store.dispatch(`${namespace}/${name}`, ...args), | |
) as ActionsMapped | |
const _getState = < | |
Module extends GenericModule, | |
State = Module['state'], | |
StateMapped = { [Name in keyof State]: ComputedRef<State[Name]> }, | |
>( | |
{ state }: GenericModule, | |
store: GenericStore, | |
namespace: string, | |
): StateMapped => | |
mapValues(state, (_, name) => | |
computed(() => store.state[namespace][name]), | |
) as StateMapped | |
const _getGetters = < | |
Module extends GenericModule, | |
Getters = Module['getters'], | |
GettersMapped = { | |
[Name in keyof Getters]: ComputedRef<ReturnType<Getters[Name]>> | |
}, | |
>( | |
{ getters }: GenericModule, | |
store: GenericStore, | |
namespace: string, | |
): GettersMapped => | |
mapValues(getters, (_, name) => | |
computed(() => store.getters[`${namespace}/${name}`]), | |
) as GettersMapped | |
export const useStore = < | |
Module extends GenericModule, | |
State = Module['state'], | |
StateMapped = { [Name in keyof State]: ComputedRef<State[Name]> }, | |
Getters = Module['getters'], | |
GettersMapped = { | |
[Name in keyof Getters]: ComputedRef<ReturnType<Getters[Name]>> | |
}, | |
Actions = Module['actions'], | |
ActionsMapped = { | |
[Name in keyof Actions]: ( | |
...args: GetRestParams<Actions[Name]> | |
) => Promise<Awaited<ReturnType<Actions[Name]>>> | |
}, | |
>( | |
module: Module, | |
): { | |
actions: ActionsMapped | |
state: StateMapped | |
getters: GettersMapped | |
} => { | |
const store = useRootStore() | |
const namespace = module.name | |
return { | |
actions: _getActions(module, store, namespace), | |
state: _getState(module, store, namespace), | |
getters: _getGetters(module, store, namespace), | |
} | |
} | |
export const useActions = < | |
Module extends GenericModule, | |
Actions = Module['actions'], | |
ActionsMapped = { | |
[Name in keyof Actions]: ( | |
...args: GetRestParams<Actions[Name]> | |
) => Promise<Awaited<ReturnType<Actions[Name]>>> | |
}, | |
>( | |
module: Module, | |
): ActionsMapped => { | |
const store = useRootStore() | |
const namespace = module.name | |
return _getActions(module, store, namespace) | |
} | |
export const useGetters = < | |
Module extends GenericModule, | |
Getters = Module['getters'], | |
GettersMapped = { | |
[Name in keyof Getters]: ComputedRef<ReturnType<Getters[Name]>> | |
}, | |
>( | |
module: Module, | |
): GettersMapped => { | |
const store = useRootStore() | |
const namespace = module.name | |
return _getGetters(module, store, namespace) | |
} | |
export const createVuexModule = < | |
State extends Record<string, unknown>, | |
Getters extends GetterTree<State, RootState>, | |
Actions extends ActionTree<State, RootState>, | |
Mutations extends MutationTree<State>, | |
>( | |
name: string, | |
{ | |
state, | |
mutations, | |
actions, | |
getters, | |
}: { | |
state: State | |
mutations: Mutations | |
actions: Actions | |
getters: Getters | |
}, | |
): { | |
name: string | |
state: State | |
mutations: Mutations | |
actions: Actions | |
getters: Getters | |
} => { | |
const structure = { state, mutations, actions, getters } | |
const moduleStructure = { namespaced: true, ...structure } | |
const hasModule = store.hasModule(name) | |
if (!hasModule) { | |
store.registerModule(name, moduleStructure) | |
} | |
if (hasModule && module.hot) { | |
store.hotUpdate({ modules: { [name]: moduleStructure } }) | |
} | |
return { name, ...structure } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Read more about this script at https://www.hendrysadrak.com/posts/vue-2-composition-api-and-vuex