A small SPA storage system based on @vue/reactivity
# With NPM
npm i -S @samatech/vue-store
# With PNPM
pnpm i -S @samatech/vue-store
A basic module with explicit typing. See here for a slightly more advanced example.
import {
IGetters,
IMutations,
IState,
useModule,
IModule,
LocalStoragePlugin,
} from '@samatech/vue-store'
export type IUserModule = IModule<IUser, IUserGetters, IUserMutations>
interface IUser extends IState {
name: string
}
interface IUserGetters extends IGetters {
upperCaseName: () => string
}
interface IUserMutations extends IMutations {
updateName: (name: string) => void
logout: () => void
}
const getDefaultUser = (): IUser => ({
name: '',
})
export const userModule = useModule<IUser, IUserGetters, IUserMutations>({
name: 'user',
version: 1,
stateInit: getDefaultUser,
getters: (state: IUser) => ({
upperCaseName: () => state.name.toUpperCase(),
}),
mutations: (state: IUser) => ({
updateName: (name: string) => (state.name = name),
logout: () => {
Object.assign(state, getDefaultUser())
},
}),
plugins: [LocalStoragePlugin],
})
Typescript's ReturnType
feature can be used to avoid the need for defining explicit interfaces:
import { LocalStoragePlugin, useModule, useRootModule } from '@samatech/vue-store'
interface IUser {
name: string
}
const getDefaultUser = (): IUser => ({
name: '',
})
const getters = (state: IUser) => ({
upperCaseName: () => state.name.toUpperCase(),
})
const mutations = (state: IUser) => ({
updateName: (name: string) => (state.name = name),
logout: () => {
Object.assign(state, getDefaultUser())
},
})
const userModule = useModule<
IUser,
ReturnType<typeof getters>,
ReturnType<typeof mutations>
>({
name: 'user-store',
version: 1,
stateInit: getDefaultUser,
getters,
mutations,
plugins: [LocalStoragePlugin],
})
export const store = useRootModule({
name: 'web-store',
version: 1,
subModules: {
user: userModule,
},
})
If a state field is set to undefined
, it will not appear in the flattened module, or be saved with the LocalStoragePlugin. It is recommended to use null
instead, and make use of strict type checking to avoid accidentally setting fields to undefined
. It is possible to add undefined
support to the LocalStoragePlugin, please file a feature request or submit a PR if you need this functionality.
Plugins can help initialize state, and operate on state when it changes. A basic LocalStoragePlugin is provided for persisting a module's state to browser storage.
Writing plugins is straightforward, just provide an object conforming to IPlugin, or a function that accepts a module parameter and returns IPlugin.
interface IPlugin<S extends IState> {
// Called when the module is initialized
onStateInit?: (state: S) => S
// Called any time the module's state changes
onDataChange?: WatchCallback<UnwrapNestedRefs<S>, UnwrapNestedRefs<S> | undefined>
}
interface MyState {
dots: string
}
const dummyPlugin: IPlugin<MyState> = {
onDataChange: (value) => {
value.dots += '.'
},
}
TODO -- details about using alongside other versions of @vue/reactivity
See the example
folder.
We use PNPM workspaces for development
# Clone
git clone git@github.com:samatechtw/vue-store
cd vue-store
# Install dependencies
pnpm install
# Run example
pnpm run all:dev
# Build
pnpm run build
MIT License © 2022 SamaTech Limited Company