Lets say I have a simple Vuex state to hold a recipe:
const state = {
recipe: {
id: '',
name: "",
ingredients : [],
}
};
Is it a good practice to instead create a recipe class holding the same data, and then in the state declare it as an instance of the class?
const state = {
recipe: new Recipe()
};
If the recipe class has methods, should those methods be proxied via getters/mutations on the vuex store, or is it okay to call the methods directly?
Compared to Vuex, Pinia provides a simpler API with less ceremony, offers Composition-API-style APIs, and most importantly, has solid type inference support when used with TypeScript.
Summary. vuex-stores provides a simple way to work with Vuex modules by allowing you to define store objects to focus on one module at a time, making it more enjoyable to leverage Vuex.
Strict mode runs a synchronous deep watcher on the state tree for detecting inappropriate mutations, and it can be quite expensive when you make large amount of mutations to the state. Make sure to turn it off in production to avoid the performance cost.
While I can not give an authoritative answer, I would say yes, you should use classes in the state. I consider this good practice in line with the Separation of Concern design principle. However, you should not have methods on those classes to call directly.
In my application, using vuex and typescript, I have written a "api-model" that represents the various parts of my API responses and requests and some as unitTree.ts
helper class code that is responsible for the handling of the enterpriseUnitsTree
part of the state, which is a local subset of the caseFullData
.
Here's how I do it in the state.ts (simplified):
import { ICaseFullDataViewModel, CaseFullDataViewModel, CaseApprovalDto, ICaseApprovalDto } from '@/api-model';
import { IEnterpriseUnitDataObjectTree } from '../code/unitTree';
export interface IEntryState {
caseValidationMessages: string[];
caseFullData: ICaseFullDataViewModel;
enterpriseUnitsTree: Array<IEnterpriseUnitDataObjectTree>;
caseApproval: ICaseApprovalDto;
}
export const state: IEntryState = {
caseValidationMessages: null,
caseFullData: new CaseFullDataViewModel(),
enterpriseUnitsTree: null,
caseApproval: new CaseApprovalDto()
};
As for getting data, I would recommend having a complete set of getters for each aspect you need. It keeps the state clean as really to be only a state, not a business/use case in itself. See below some getters for parts of the above data. For example, I am using external code in unitTree.ts
to extract a specific item of enterpriseUnitsTree
from the store.
Here's my code in getters.ts (simplified):
import { IRootState } from '@/store';
import { GetterTree } from 'vuex';
import { unitTree } from '../code/unitTree';
import { IEntryState } from './state';
export const CASE_ID = 'caseId';
export const CASE_FULL_DATA = 'caseFullData';
export const UNITS_SORTED_AS_TREE = 'unitsSortedAsTree';
export const FIRST_UNIT = 'firstUnit';
export const getters: GetterTree<IEntryState, IRootState> = {
[CASE_ID]: state => state.caseFullData?.caseId,
[CASE_FULL_DATA]: state => state.caseFullData,
[UNITS_SORTED_AS_TREE]: state => {
return state.enterpriseUnitsTree;
},
[FIRST_UNIT]: state => () => {
const indexMap = unitTree.getIndexMap(state.enterpriseUnitsTree);
const firstUnitIdentifier = indexMap.get(0);
return firstUnitIdentifier;
}
//....
};
In the mutations.ts
, I do mutate the the enterpriseUnitsTree
, as needed, when receiving a commit the the respective data:
Here's my code in mutations.ts (simplified):
import { MutationTree } from 'vuex';
import {
ICaseFullDataViewModel
} from '@/api-viewmodel';
import { IEntryState } from './state';
import { unitTree } from '../code/unitTree';
export const MAPCASEFULLDATA = 'mapCaseFullData';
//....
export const mutations: MutationTree<IEntryState> = {
[MAPCASEFULLDATA](state, value: ICaseFullDataViewModel) {
state.caseFullData = value;
//... some sorting and tree building using code from unitTree
state.enterpriseUnitsTree = sortedEnterpriseUnits;
},
//.......
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With