前言
Pinia
,作为Vue官方团队新推荐的数据管理器,采用了Composition API设计,为开发者提供了更为轻松的上手体验,同时保留了许多优秀的特性。
在本文中,我们将不深入介绍具体的使用方法,而是重点分享如何在项目中更有效地运用和管理Pinia store
。这里的实践经验主要来源于 Ray Template。
通过采用Pinia
,你可以体验到更简洁而强大的状态管理,其设计理念不仅减轻了学习负担,还为你提供了更丰富的特性。如果你希望更深入地了解如何在项目中最大程度地发挥Pinia
的优势,请参考 Ray Template。
起步
在企业级项目中,模块的良好维护至关重要,特别是对于store
仓库,以下几个方面是需要考虑的关键点:
-
模块化组织: 将
store
拆分为逻辑相关的模块,以提高可维护性和可扩展性。每个模块应专注于一个明确的功能领域,避免功能耦合。 -
命名空间: 使用命名空间来避免命名冲突,确保模块在全局命名空间中是唯一的。这样可以有效防止不同模块之间的状态或操作互相影响。
-
文件结构: 组织清晰的文件结构对于长期维护至关重要。可以按照模块来组织文件,也可以按照功能来组织。在项目结构清晰的基础上,寻找和修改代码将更加轻松。
-
持久化: 对于需要持久化的状态,考虑使用合适的方案,例如将状态存储在本地存储或会话存储中。这有助于在刷新页面或重新加载应用时保持状态。
通过关注这些方面,可以更好地组织和维护store
仓库,使其更符合企业级项目的需求。
规划模块
一般来说,会在 src
目录下创建一个 store
文件夹,当作项目的数据仓库。
css
├── src
│ ├── store
目前的项目结构如上。
命名空间
在使用 pinia
的 defineStore
进行仓库初始化时,有一些关键点需要特别注意:
-
关注
key
的唯一性:defineStore
方法中的key
应该是唯一的,以确保在整个应用中不会出现冲突。这有助于pinia
正确识别和管理不同的仓库。 -
不支持
symbol
类型:defineStore
不支持使用symbol
类型作为仓库的key
,因为它要求key
必须是一个字符串。如果使用symbol
,将收到 TypeScript 的类型报错。
通过确保 key
的唯一性和避免使用 symbol
,可以更好地使用 pinia
的 defineStore
方法初始化仓库,并有效地避免潜在的问题。
文件结构
一个良好的文件结构规划对于阅读和管理 pinia
仓库至关重要。以下是一个推荐的文件结构管理方式:
go
├── store
│ ├── hooks
│ │ ├── useUserStore.ts
│ ├── user
│ │ ├── type.ts index.ts helper.ts ...
│ index.ts
在这个结构中:
store
文件夹包含了所有的pinia
仓库模块。- 每个模块有一个独立的文件夹,文件夹中包含了
index.ts
、type.ts
、helper.ts
等文件,便于分别管理不同的模块功能。 index.ts
文件用于导出该模块的store
实例。
这种结构有助于保持代码的整洁性,提高可读性,便于模块的维护和扩展。在 index.ts
中导入仓库模块,从而在应用中使用。
pinia
持久化
pinia-plugin-persistedstate
插件是一个方便的插件,允许你为每个仓库模块进行单独的持久化状态配置。它的使用方式简便,具体的详细信息可以在插件的 GitHub 页面上查看。
这个插件的主要优点有:
- 仓库级配置: 你可以为每个仓库模块单独配置是否需要持久化状态。
- 灵活的配置选项: 提供了灵活的配置选项,可以根据项目的需要进行定制。
- 简化持久化逻辑: 避免了手动处理本地存储的逻辑,使持久化状态的管理更为简便。
使用这个插件可以很好地管理和保持仓库状态的持久性,确保用户在刷新页面或重新打开应用时能够保留其状态。
理论存在,上手代码
假设我们需要维护一个 user store
模块。
type.ts
类型
ts
export interface UserState {
name: string
age: number
address: string
}
index.ts
user 仓库模块
ts
import type { UserState } from './type'
export const piniaUserStore = defineStore(
'demo',
() => {
const userState = ref<UserState | null>(null)
const setUserState = (user: UserState) => {
userState.value = user
}
return {
userState,
setUserState,
}
},
{
persist: {
key: 'piniaUserStore',
paths: ['userState'],
storage: sessionStorage | localStorage,
},
},
)
hooks/useUserStore
getters, actions
这里解释一下为什么不将该代码写在对应的仓库模块下:
- 这么写更符合
hooks
概念 - 尽可能避免直接去操作仓库中的逻辑
- 统一在
hooks
中去维护所有的getters
,acitons
ts
import { piniaUserStore } from '../store/user/index'
export const useUserGetters = () => {
const variable = piniaDemoStore()
const getUserState = computed(() => variable.userState)
return {
getUserState,
}
}
export const useUserActions = () => {
const { setUserState } = piniaDemoStore()
return {
setUserState,
}
}
store/index.ts
导出所有仓库模块
ts
export { useUserGetters, useUserActions } from './hooks/useUserStore'
页面使用
1s
后页面将会显示最新的 user
信息。
vue
<template>
<ul>
<li>姓名:{{ getUserState.name }}</li>
<li>年龄:{{ getUserState.age }}</li>
<li>地址:{{ getUserState.address }}</li>
</ul>
</template>
<script setup lang="ts">
import { useUserGetters, useUserActions } from '@/store'
const { getUserState } = useUserGetters() // 获取最新 userState
const { setUserState } = useUserActions() // 获取设置方法
function getUser() {
setTimeout(() => {
setUserState({
name: '章三',
age: 19,
address: '中国',
})
}, 1000)
}
getUser()
</script>
最后
所有代码可在 Ray Template Store 中查看。
如果对您有所帮助,可以给项目和文章点个赞~~