Corecturi și reformulări:
Am trecut prin asta. Pentru noi, cea mai bună soluție a fost utilizarea https://pinia.vuejs.org/, unde, în principiu, am definit atât starea componentei, cât și metodele care efectuau apeluri către SDK-ul de API.
Prin adoptarea acestei abordări, componente nu mai conțineau:
- stări de date din surse externe (remote)
- metode de apelare directă a SDK-ului
Un avantaj suplimentar este că, prin utilizarea Pinia, poți folosi plugin-uri, de exemplu, pentru a implementa persistența în localstorage pentru stări.
De asemenea, pentru store-urile Pinia, poți crea factory-uri care să genereze store-uri precompletate cu pattern-uri de formulare, inclusiv starea formData, erori, etc.
Un exemplu de astfel de factory. Posibil ca acest cod sa nu compilze. You get the idea
import { defineStore } from 'pinia';
interface BaseStoreState {
initialized: boolean;
loading: boolean;
errors: Record<string, string>;
id: null | number;
}
type StoreState<S> = BaseStoreState & S;
type StoreGetters<G> = {
hasLoading(state: StoreState<G>): boolean;
loadedItem(state: StoreState<G>): G['item'];
};
type StoreActions<A, S> = {
setGeneralError(error: string): void;
reject(error: string): Promise<void>;
reset(): void;
action(promise: () => Promise<any>, needsId?: boolean): Promise<any>;
load(item: S['item']): void;
} & A;
export const storeContextActionFactory = <S, A, G>(
name: string,
state: Partial<BaseStoreState> & S,
actions = {} as Partial<StoreActions<A, S>> & A,
getters = {} as Partial<StoreGetters<G>> & G,
extra = {},
) => {
return defineStore(name, {
state: () => ({
name,
item: {} as S['item'],
initialized: false,
loading: false,
errors: {},
id: null,
...state,
}) as StoreState<S>,
getters: {
hasLoading: (state): boolean => {
return state.loading;
},
loadedItem: (state): S['item'] => {
return state.item;
},
...getters,
} as StoreGetters<G>,
actions: {
setGeneralError(this: StoreActions<A, S>, error: string) {
this.errors.general = error;
},
reject(this: StoreActions<A, S>, error: string): Promise<void> {
this.setGeneralError(error);
return Promise.reject(this.errors);
},
reset(this: StoreActions<A, S>) {
console.log(`### resetting ${name} store`);
this.$reset();
},
action(this: StoreActions<A, S>, promise: () => Promise<any>, needsId = true): Promise<any> {
console.log(`### action called on ${name} store`);
return new Promise((resolve, reject) => {
if (this.hasLoading) {
console.warn(`Other action in progress. Please wait...`);
this.errors.general = `Other action in progress. Please wait...`;
return reject(this.errors);
}
if (needsId && !this.id) {
console.warn(`No id provided`);
this.errors.general = `No id provided`;
reject(this.errors);
}
this.loading = true;
promise()
.then((response) => {
resolve(response);
})
.catch((response) => {
this.errors = response.response.data.errors;
if (
Object.keys(this.errors).length === 0 &&
this.errors.constructor === Object
) {
this.errors.general = response.response.data.message;
}
reject(this.errors);
})
.finally(() => {
this.loading = false;
});
});
},
load(this: StoreActions<A, S>, item: S['item']) {
this.item = item;
this.initialized = true;
this.loading = false;
this.errors = {};
this.id = item?.id || null;
},
...actions,
} as StoreActions<A, S>,
...extra,
});
};
P.S. As putea spune ca Pinia nu e chiar 3rd party, atata timp cat il recomanda si vue 