# Store > Vuex-like state management pattern with Actions, Getters, Mutations, and State classes. --- ## Overview The store implements a Vuex-like pattern using separate classes for State, Actions, Getters, and Mutations. It uses Vuex's `createStore` function. --- ## Architecture ``` Store ├── State (reactive data) ├── Actions (async operations that commit mutations) ├── Mutations (synchronous state changes) └── Getters (computed values) ``` --- ## State Class **File**: `/home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts` ```typescript export class State { dict = { active_status: { A: "启用", B: "禁用", }, }; roles = {}; menus = []; roleRefresh = true; style = Styles.plain; size = Size.normal; actions = []; user = {}; actionPers = {}; refreshFlags = new Map(); } ``` ### State Properties | Property | Type | Description | |----------|------|-------------| | `dict` | object | Dictionary mappings by code | | `roles` | object | Role ID to name mapping | | `menus` | array | User menu permissions | | `roleRefresh` | boolean | Flag to trigger role refresh | | `style` | Styles.plain | Current theme style | | `size` | Size.normal | Current size variant | | `actions` | array | User action permissions | | `user` | object | Current user object | | `actionPers` | object | Action permission mappings | | `refreshFlags` | Map | Refresh flag tokens per flag name | --- ## Actions Class **File**: `/home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts` ```typescript export class Actions { getDictMap = ({ state, commit }, codes) => { if (codes == null) { return; } const arr: Array = []; for (let i = 0; i < codes.length; i++) { const code = codes[i]; state.dict[code] || arr.push(code); } if (arr.length == 0) { return; } getByCodes({ codes: arr.join() }).then((rsp: any) => { if (rsp) { for (let i = 0; i < arr.length; i++) { const key = arr[i]; const dict = {}; if (rsp[key]) { rsp[key].forEach((item) => { dict[item.code] = item.name; }); } commit("updateDict", [key, dict]); } } }); }; getRoleMap = ({ state, commit }) => { state.roleRefresh && mapping().then((rsp) => { commit("updateState", ["roles", rsp]); commit("updateState", ["roleRefresh", false]); }); }; getMenus = ({ state, commit }) => { getMenus().then((rsp) => commit("updateState", ["menus", rsp])); }; getMyActions = ({ state, commit }, content) => { getActions(content).then((rsp) => commit("updateState", ["actions", rsp])); }; login = (store) => { const { state, commit } = store; state.size.headHeight = state.size.head + "px"; state.size.asideWidth = state.size.aside + "px"; commit("initSize"); this.getMenus(store); }; setRefreshFlag = ({ state, commit }, flags: string[]) => { commit("setRefreshFlag", flags); }; unsetRefreshFlag = ({ state, commit }, params: { flags: string[]; token: string }) => { commit("unsetRefreshFlag", params); }; } ``` ### Actions Pattern - Actions receive Vuex store object with `state`, `commit`, `dispatch` - Actions call API functions and commit mutations - Actions never directly modify state - Actions can call other actions via `dispatch` ### Key Actions | Action | Description | |--------|-------------| | `getDictMap` | Fetches dictionary entries by codes, caches in state | | `getRoleMap` | Fetches role mappings if refresh is needed | | `getMenus` | Fetches user menu permissions | | `getMyActions` | Fetches user action permissions | | `login` | Initializes size settings and fetches menus | | `setRefreshFlag` | Creates empty refresh flag sets | | `unsetRefreshFlag` | Adds token to refresh flag sets | --- ## Mutations Class **File**: `/home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts` ```typescript export class Mutations { updateState = (state, [k, v]) => { state[k] = v; }; initSize = (state, param) => { const size = state.size; const aside = parseInt(size.asideWidth); const head = parseInt(size.headHeight); const mainPad = parseInt(size.mainPad); const searchRow = parseInt(size.searchRowHeight); const searchRowPad = parseInt(size.searchRowPad); const headRightWidth = parseInt(size.headRightWidth); if (param) { size.height = param[0]; size.width = param[1]; } size.mainHeight = Math.floor(size.height - head) + "px"; size.tableHeight = size.height - 2 * (mainPad + searchRowPad) - 3 - searchRow - head; size.pTableHeight = size.tableHeight - size.pageHeight; size.headLeftWidth = size.width - aside - headRightWidth - 20 + "px"; }; updateDict = (state, param) => { state.dict[param[0]] = param[1]; }; setRefreshFlag = (state, flags: string[]) => { for (const flag of flags) { state.refreshFlags.set(flag, new Set()); } }; unsetRefreshFlag = (state, { flags, token }: { flags: string[]; token: string }) => { for (const flag of flags) { if (!state.refreshFlags.has(flag)) { state.refreshFlags.set(flag, new Set()); } state.refreshFlags.get(flag).add(token); } }; } ``` ### Mutations Pattern - Mutations receive `state` directly - Mutations are synchronous - Mutations use array destructuring for multiple parameters: `([k, v])` - Mutations directly modify state properties ### Key Mutations | Mutation | Description | |----------|-------------| | `updateState` | Generic state update: `commit("updateState", ["key", value])` | | `initSize` | Initializes size-dependent calculated values | | `updateDict` | Updates dictionary entry: `commit("updateDict", [code, mapping])` | | `setRefreshFlag` | Creates new refresh flag with empty Set | | `unsetRefreshFlag` | Adds token to refresh flag Set | --- ## Getters Class **File**: `/home/hechang27/Documents/sprt/noob-components/plugs/store/index.ts` ```typescript export class Getters { menuIconSize = (state) => { return state.size.menuIconSize; }; } ``` ### Getters Pattern - Getters receive `state` as first parameter - Getters compute and return derived values - Getters are cached based on dependencies --- ## Store Creation ```typescript export interface StoreOptions { state?: State; getters?: Getters; actions?; mutations?: Mutations; modules?; plugins?; strict?: boolean; devtools?: boolean; } export const createStore = (options) => { return create(options); }; ``` --- ## Usage in Component ```typescript import { createStore } from "vuex"; import { State, Actions, Mutations, Getters } from "./store"; const store = createStore({ state: new State(), getters: new Getters(), actions: new Actions(), mutations: new Mutations(), strict: true, }); ``` --- ## Anti-Patterns 1. **Never modify state directly in actions** - Always use `commit` to call mutations 2. **Do not put async logic in mutations** - Mutations must be synchronous 3. **Do not use mutation names as variables** - Always use string literals for mutation names 4. **Do not skip the `initSize` mutation** - Without it, derived values like `mainHeight` will be incorrect --- **Language**: English