其实pinia使用state就够了

1,265 阅读2分钟

其实pinia使用state就够了

在pinia中使用state、getter、action中区划分数据和函数其实仍然是类似于option api的使用方式,这也导致了使用这种方式配合ts时类型支持仍然不够友好,也没有办法对store做组合(没办法得到正确的类型提示),但如果我们使用computed代替getter,并且action也放到state里面就可以做到了

封装基础store(封装大部分模块都要遇到的增删改查功能)

// store/basic.ts
import { computed, reactive, Ref, ref } from "vue";
import { http } from '@/http/http';
import { ElMessage } from "element-plus";
import { AxiosRequestConfig } from "axios";


export type AddConfig = boolean | undefined | (Partial<{
  /**请求玩数据是否更新列表 */
  $refresh: boolean,
}> & AxiosRequestConfig)

export type DeleteConfig = AddConfig;

const parseConfig = (config: AddConfig | DeleteConfig) => {
  if(config === undefined || typeof config === 'boolean') {
    return {
      $refresh: !!config
    }
  } else {
    return config;
  }
}

export const useBasicStore = <DataType>(url: string = '') => {
  /**模块列表数据 */
  const list = ref([]) as Ref<DataType[]>;
  const pageInfo = reactive({
    page: 0,
    page_size: 10,
    total: 0,
  })
  /**模块详情数据 */
  const data = ref(null) as Ref<DataType | null>;
  /** 草稿数据 用于新增 */
  const draftData = ref({}) as Ref<Partial<DataType>>;
  /**列表激活模块 */
  const current = ref(null) as Ref<DataType | null>;
  /** 请求指示器 */
  const pending = reactive({
    get: false,
    delete: false,
    put: false,
    post: false,
  })
  
  const isPending = computed(() => {
    return Object.values(pending).some(v => v);
  });
  
  const onFetch = <T>(promise: T, key: keyof typeof pending): Promise<T> => {
    pending[key] = true;
    return Promise.resolve(promise).finally(() => pending[key] = false);
  }

  const getList = async(params:IHttp.BasicRequestListQuery = {}, config?: AxiosRequestConfig) => {
    config = config || {};
    const result = await onFetch(http.get<IHttp.BasicResponseList<DataType>>(url, { params, ...config }), 'get');

    pageInfo.page = result.data.page;
    pageInfo.page_size = result.data.pageSize;
    pageInfo.total = result.data.totalPage;

    list.value = result.data.data;

    return list;
  }

  const getDetail = async (id: string | number, config?: AxiosRequestConfig) => {
    config = config || {};
    const result = await onFetch(http.get<DataType>(`${url}/${id}`, config), 'get');
    data.value = result.data;
    return data;
  }

  const update = async (id: string | number, payload: Partial<DataType>) => {
    const result = await onFetch(http.put(`${url}/${id}`, payload), 'put');
    ElMessage.success(`更新成功`);
    return result.data;
  }
  
  const add = async (payload: Partial<DataType>, config: AddConfig) => {
    config = parseConfig(config);
    const result = await onFetch(http.post(`${url}`, payload, config), 'post');
    ElMessage.success(`添加成功`);
    draftData.value = {};
    config.$refresh && getList();
    return result;
  }

  const del = async (id: string | number, config: DeleteConfig) => {
    config = parseConfig(config);
    const result = await onFetch(http.delete(`${url}/${id}`, config), 'post');
    ElMessage.success(`删除成功`);
    config.$refresh && getList();
    return result;
  }

  return {
    list,
    data,
    current,
    draftData,
    pending,
    isPending,
    getList,
    getDetail,
    update,
    add,
    del,
  }
};

使用

// store/test.ts
import { defineStore } from "pinia";
import { useBasicStore } from "./base";
type TestState = {
  name: string,
  hobby: string []
}
// 直接使用
export const useTest = defineStore('test', () => useBasicStore<TestState>('/api/test'));

export const useTest1 = defineStore('test1', () => {

  const state = useBasicStore<TestState>('/api/test');

  return {
    ...state,
    // 增加模块内部的行为或者覆盖basicStore内的默认行为
    ...someState
    ...someAction
  }
});

useTest().getList().then(res => {
  //智能提示
  res.data // TestState[]
})