pinia结合ts的项目实践

2,110 阅读2分钟

老婆镇楼!

最近使用pinia作为新项目的状态管理,无论是定义还是使用都很简单易用,也结合ts和pinia选项式 (setup的也很喜欢,很自由,但个人觉得选项式更适合团队理解,简单明了) 整理了一套store的套路结构。

目录结构

.
|-- data                  # data store 
|   |-- actions-types.ts  # action接口定义
|   |-- actions.ts        # action定义
|   |-- getters.ts        # getters定义
|   |-- state.ts          # state定义
|   `-- index.ts          # 导出文件
|-- index.ts              # 导出文件
|-- type.ts               # store泛型工具

type.ts

这里只放了一个结合defineStore actions options和 自定义的stateactions接口,创建给actions.ts使用的泛型工具。方便actions.ts的ts提示。

import { PiniaCustomProperties, StateTree, _GettersTree, _StoreWithGetters, _StoreWithState } from 'pinia';
import { UnwrapRef } from 'vue';

export type CreateActions<Id extends string, S extends StateTree, A> = A &
	ThisType<A & UnwrapRef<S> & _StoreWithState<Id, S, _GettersTree<S>, A> & _StoreWithGetters<_GettersTree<S>> & PiniaCustomProperties>;
        
export type CreateGetters<S extends StateTree, G extends _GettersTree<S>> = G &
	ThisType<UnwrapRef<S> & _StoreWithGetters<G> & PiniaCustomProperties> &
	_GettersTree<S>;

index.ts

这是store的主要输出文件,导出的registerStore负责在main.ts初始化。

import { useStore as dataStore, DataStore } from './data';

export interface IAppStore {
	data: ReturnType<DataStore>;
}

const store: IAppStore = {} as IAppStore;

/**
 * 注册app状态库
 */
export const registerStore = () => {
	store.data = dataStore();
};
export default store;


main.ts

import { createApp, Component } from 'vue';
import { createPinia } from 'pinia';
import { registerStore } from '@/store';
import App from './App.vue';

const app = createApp(App);
app.use(createPinia());

// 注册pinia状态管理库
registerStore();

app.mount('#app');

state.ts

state定义

export interface DataState {
	users:Map<string, { [key: string]: SafeAny }>
}

export const state: DataState = {
	users: []
};

getters.ts

getters定义

import { _GettersTree } from 'pinia';
import { CreateGetters } from '../type';
import { DataState } from './state';

export type Getters = {
	/** 有未读信息的 */
	hadUnread(): boolean;
};

export type DataGetters = CreateGetters<DataState, Getters>;

export const getters: DataGetters = {
	hadUnread() {
		return this.notify.system.unreadNum > 0;
	}
};

actions-types.ts

使用CreateActions创建的类型,可以完美得到的this方法和state的提示

import { SafeAny } from '@/app/shared/types/yacommon';
import { CreateActions } from '../type';
import { DataState } from './state';

interface Action {
	queryUsers(): void;	
}

export type DateActions = CreateActions<string, DataState, Action>;

actions.ts

import { DateActions } from './actions-types';

export const actions: DateActions = {
	queryUsers() {
            ...
        }
};

data/index.ts

选项式组合defineStore

import { defineStore, StoreDefinition, acceptHMRUpdate } from 'pinia';
import { state, DataState } from './state';
import { actions } from './actions';
import { DateActions } from './actions-types';
import { getters, DataGetters } from './getters';

export type DataStore = StoreDefinition<string, DataState, DataGetters, DateActions>;

export const useStore: DataStore = defineStore('data', {
	state: () => state,
	actions,
	getters
});

if (import.meta.hot) import.meta.hot.accept(acceptHMRUpdate(useStore, import.meta.hot));

关于 acceptHMRUpdate

开发过程中发现,发现vite在热更新时,有store丢失的情况,在pinia的issues找到了相同的问题 ->传送门

  • pinia: v2.0.14
  • vite: v2.9.12
if (import.meta.hot) import.meta.hot.accept(acceptHMRUpdate(useStore, import.meta.hot));

结语

这样一套下来,开发体验理解简答,已维护。 使用只需要。

import store from '@/store';

store.data.queryUsers();

console.log(store.data.users);

欢迎大家实践!