【问题标题】:How to use other store module getters/actions/mutations with Vuex 4 and TypeScript如何在 Vuex 4 和 TypeScript 中使用其他存储模块 getter/actions/mutations
【发布时间】:2021-08-08 19:58:53
【问题描述】:

我正在使用 TypeScript 和 Vuex4 开发一个 Vue 3 项目。 现在,我正在使用带有 TS 的 vuex 中的每个商店模块使用样板声明方法。 看起来像这样: 或者如果我的代码可读性不够,这里是我用来指导我的:https://betterprogramming.pub/the-state-of-typed-vuex-the-cleanest-approach-2358ee05d230

//#region Store
export const state: State = {
  stateVar: null,
  isError: false,
};

export const getters: GetterTree<State, RootState> & Getters = {
  getStateVar: state => state.stateVar,
  getIsError: state => state.isError,
};

export const mutations: MutationTree<State> & Mutations = {
  [ModuleMutationTypes.setStateVar](state: State, payload: StateVarType) {
    state.stateVar = payload;
  },
  [ModuleMutationTypes.setIsError](state: State, payload: boolean) {
    state.isError = payload;
  },
};

export const actions: ActionTree<State, RootState> & Actions = {
  async [ModuleActionTypes.doRequest]({ commit, getters }) {
    //do something and commit it 
    // for example here i would like to access the getters or action from another store how is that possible 
    commit(ModuleMutationTypes.setStateVar, someValue);
  },
};
//#endregion Store

//#region Store Type
export type State = {
  someStateVar: SomeStateVarType;
  isError: boolean;
};

export type Getters = {
  getStateVar(state: State): someStateVarType;
  getIsError(state: State): boolean;
};

export type Mutations<S = State> = {
  [ModuleMutationTypes.setStateVar](state: S, payload: SomeSTateVarType): void;
  [ModuleMutationTypes.setIsError](state: S, payload: boolean): void;
};

export interface Actions {
  [ModuleActionTypes.doRequest](context: AugmentedActionContext): Promise<any>;
}

type AugmentedActionContext = {
  commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>;
  getters: {
    [K in keyof Getters]: ReturnType<Getters[K]>;
  };
  dispatch<K extends keyof Actions>(
    key: K,
    payload?: Parameters<Actions[K]>[1],
    options?: DispatchOptions
  ): ReturnType<Actions[K]>;
} & Omit<ActionContext<State, RootState>, 'commit' | 'getters' | 'dispatch'>;
//#endregion Store Type

//#region Store Module
export type ModuleStore<S = State> = Omit<VuexStore<S>, 'getters' | 'commit' | 'dispatch'> & {
  commit<K extends keyof Mutations, P extends Parameters<Mutations[K]>[1]>(
    key: K,
    payload: P,
    options?: CommitOptions
  ): ReturnType<Mutations[K]>;
} & {
  dispatch<K extends keyof Actions>(
    key: K,
    payload?: Parameters<Actions[K]>[1],
    options?: DispatchOptions
  ): ReturnType<Actions[K]>;
} & {
  getters: {
    [K in keyof Getters]: ReturnType<Getters[K]>;
  };
};

export const store: Module<State, RootState> = {
  state,
  mutations,
  getters,
  actions,
  //namespaced also breaks everything
  // But without it, a bigger store might have clashes in namings
  // namespaced: true,
};
//#endregion Store Type & Module

现在正如你所见,这让我重复了很多很多东西,但是在 Vuex 5 之前我不知道是否还有其他更好的解决方案。 另外我对 TypeScript 很陌生,我只是使用这个样板作为模板来让我的商店打字。

我的主要问题是:

  1. 如何访问其他模块的 getter 或特定模块中的操作或突变,如果我可以让 RootGetters 和 RootActions 工作,我什至会很高兴,但我尝试过,但无法使其工作,但正如我提到的我是新手,所以也许我不知道更好。或者我导入这个导出的 const 存储:Module ... 就那么容易,这会使我的代码变得笨拙,因为当我想使用来自 4 个不同模块的 getter 时,我需要导入所有 4 个?李>
  2. 我怎样才能使这些模块命名空间,我有一些相当大的商店,谈论大约 500 行和很多东西,所以名字不冲突会很好吗?也许这样可以更容易地在其他模块中使用它们?

即使你不能提供完整的答案,我也很乐意尝试你们提出的每一个建议,因为我很迷茫。


**更新:** 您可以看到关于如何使用 allAction|MutationTypes 的公认答案,只需导入它而不是子模块特定的 Action|MutationTypes 并在调用调度或提交时使用它。

至于名称间距,这仍然是一个开放式主题,请随时分享。

由于答案不包括吸气剂,经过反复试验,我最终这样做了:

//./store/index.ts
import {
  Getters as AxiosGetters,
} from '@/store/modules/axios/axios';
import {
  Getters as SiteSettingsGetters,
} from '@/store/modules/site_settings/site_settings';
import {
  Getters as UserGetters
} from '@/store/modules/user/user';

export interface RootGetters extends AxiosGetters, SiteSettingsGetters, UserGetters {}


//./some-store/module.ts
import {RootGetters} from '@/store';

type AugmentedActionContext = {
  commit<K extends keyof Mutations>(key: K, payload: Parameters<Mutations[K]>[1]): ReturnType<Mutations[K]>;
  getters: {
    [K in keyof Getters]: ReturnType<Getters[K]>;
  };
  rootGetters: {
    [K in keyof RootGetters]: ReturnType<RootGetters[K]>;
  };
  dispatch<K extends keyof Actions>(
    key: K,
    payload?: Parameters<Actions[K]>[1],
    options?: DispatchOptions
  ): ReturnType<Actions[K]>;
} & Omit<ActionContext<State, RootState>, 'commit' | 'getters' | 'dispatch' | 'rootGetters'>;

export interface Actions {
  [ActionTypes.doSomething](context: AugmentedActionContext): Promise<void>;
}

export const actions: ActionTree<State, RootState> & Actions = {
  [ActionTypes.doSomething]({ commit, rootGetters, dispatch }) {
      // You can now use getters From other stores, and also the mutation and action useing All(name)Types and having them typed
  },

【问题讨论】:

    标签: typescript vue.js vuex vuejs3 vuex4


    【解决方案1】:

    要访问其他模块,您可以定义每个模块的动作/变异类型并像这样导入所有模块。

    示例动作类型

    // store/action-types.ts
    import { ActionTypes as rootActionTypes } from "./modules/root/action-types";
    import { ActionTypes as authUserActionTypes } from "./modules/authUser/action-types";
    import { ActionTypes as counterActionTypes } from "./modules/counter/action-types";
    
    
    export const AllActionTypes = {
      ...authUserActionTypes,
      ...rootActionTypes,
      ...counterActionTypes,
    };
    
    

    在组件中你可以像这样使用。

    import { useStore } from "../../composables/useStore";
    import { AllActionTypes } from "../../store/action-types";
    
    
    // setup()
    
        const store = useStore();
    
        onMounted(async () => {
          await store.dispatch(AllActionTypes.GET_USERS).catch((e) => {
            console.log(e);
          });
          await store.dispatch(AllActionTypes.GET_COUNT).catch((e) => {
            console.log(e);
          });
        });
    

    对于您的第二个问题,这就是我一直在命名空间的方式。

    // store/index.ts
    import { createStore } from "vuex";
    import { IRootState } from "./interfaces";
    import { AuthUserStoreModuleTypes } from "./modules/authUser/types";
    import { CounterStoreModuleTypes } from "./modules/counter/types";
    import { RootStoreModuleTypes } from "./modules/root/types";
    
    // all the modules are registered in the root
    import root from "./modules/root";
    
    export const store = createStore<IRootState>(root);
    
    // namespacing
    type StoreModules = {
      counter: CounterStoreModuleTypes;
      root: RootStoreModuleTypes;
      authUser: AuthUserStoreModuleTypes;
    };
    
    export type Store = CounterStoreModuleTypes<Pick<StoreModules, "counter">> &
      RootStoreModuleTypes<Pick<StoreModules, "root">> &
      AuthUserStoreModuleTypes<Pick<StoreModules, "authUser">>;
    
    

    【讨论】:

    • 太棒了,这看起来很棒,我还有一个问题,因为你的答案没有涵盖它,getter 如何在全球范围内访问?此外,您已经向我展示了在组件中使用的 allActionTypes 的示例,但这并不是一个如此胖的问题,而是我如何在其他商店中使用它们。这也适用于吸气剂?
    猜你喜欢
    • 2020-01-18
    • 2020-05-14
    • 2021-08-25
    • 2023-04-08
    • 2018-10-24
    • 1970-01-01
    • 2019-03-22
    • 2021-07-15
    • 2021-09-15
    相关资源
    最近更新 更多