【大厂企业级项目架构】之状态管理
这是大厂企业级项目架构
系列的第六篇,这系列的文章如下:
- 【大厂企业级项目架构】之项目搭建和代码规范
- 【大厂企业级项目架构】之提交规范
- 【大厂企业级项目架构】之vite基础配置与多环境区分
- 【大厂企业级项目架构】之项目接入路由
- 【大厂企业级项目架构】之网络请求封装和接口管理
- 【大厂企业级项目架构】之状态管理
- 【大厂企业级项目架构】之样式方案
本篇文章比较短,因为pinia
使用起来非常简单,大概花个5分钟就能看完本文。
通常一个有一定规模的前端项目,组件间共享状态是很常见且必备的。本次我们作为一个企业级的项目,肯定也需要共享状态,我们会选用pinia
来作为状态管理方案。
pinia
对ts有良好的支持,也很简单易用,使用上基本与vuex
相同,并且pinia
本身是扁平化的设计,就是说每个store都独立的,可以更好的做模块分割,所以是一个不错的选择。
本文要做的目标如下:
- 接入
pinia
,划分好模块 - 支持持久化存储
接下来跟着我一起学习吧。
pinia基本使用
安装
pnpm i pinia
简单使用
其实pinia
的使用非常简单,首先我们需要在项目入口文件main.ts
里注册pinia
import { createPinia } from 'pinia';
app.use(createPinia());
然后在我们项目src
新建store
文件夹,用于存放状态管理相关的源码。
假设我们有一个用户模块,我们可以建一个useUserStore.ts
来存放用户的状态
import { defineStore } from 'pinia';
// 注册用户模块
export default defineStore('user', {
// 这里用于存放相应模块的状态
state: () => {
return {
username: 'xxx',
// ...
};
},
// 在这里改变模块的状态
actions: {
setUsername(name) {
this.username = name;
}
},
});
定义好模块之后,就可以在其他需要使用这个模块数据的地方读取它的状态了,假如你有一个用户信息的页面UserInfo.vue
,就可以像如下一样读取模块状态了。
<script lang="ts" setup>
import useUserStore from '@/store/useUserStore';
import { computed } from 'vue';
const userInfo = computed(() => useUserStore());
</script>
<template>
{{ userInfo.username }}
</template>
### 划分模块
上面简单演示了`pinia`是如何使用的,但是实际开发中,我们不可能把所有状态都全部写在一个文件中,我们会划分不同的模块来存放相应模块下的状态。而`pinia`的模块不像`vuex`一样是嵌套结构的,它采用了扁平化的设计,也就是说一个store就对应一个模块,各模块之间互不影响,所以我们只需要为相应模块创建store就可以了。
目录结构如下:
```sh
store
├── index.ts 主入口
└── modules 存放不同模块的状态
├── demo1.ts demo1的状态
.....
├── permission.ts 权限相关的状态
└── user.ts 用户模块相关的状态
上面modules
目录下每个模块的状态管理都是独立的,互不影响,你可以在里面写自己的state/getters/actions
,使用的时候,需要用到哪个模块,就导入哪个模块即可,相当简单方便。
以user.ts
为例举个具体的例子,user.ts
的内容如下
import { defineStore } from 'pinia';
// 注册用户模块
export default defineStore('user', {
// 这里用于存放相应模块的状态
state: () => {
return {
username: 'xxx',
// ...
};
},
// 在这里改变模块的状态
actions: {
setUsername(name) {
this.username = name;
}
},
// getters
getters: {
// 这里可以对状态进行转换后返回,类似计算属性
getUsername() {
return this.username;
}
}
});
需要注意的是pinia
没有mutation
,不管是同步还是异步修改状态都只需要在actions里修改即可,你如果有使用过vuex
,那pinia
上手还是毫无难度的
后续每个需要单独划分出来的模块,都只需要像上面一样定义store
即可。
响应性处理
需要注意的是,当我们在业务层结构出store
中的状态时,会失去响应性,此时有几种解决办法,一个是用compute将取出的状态包装一层,另一个则是通过pinia
提供的storeToRefs
包装一下,以保证这个取出来的属性的响应性,具体代码如下:
<script lang="ts" setup>
import useUserStore from '@/store/useUserStore';
import { computed } from 'vue';
import { storeToRefs } from 'storeToRefs';
// 方法一: 通过computed包装
// const username = computed(() => useUserStore().username);
// 方法二: 通过storeToRefs
const { username } = storeToRefs(userUserStore());
</script>
<template>
{{ username }}
</template>
状态持久化
在某些场景下,我们可能需要对数据进行持久化。而对于需要被持久化的数据,我们一般是通过localStorage
来做存储,而此时我们也可以通过pinia
的插件pinia-plugin-persistedstate
帮我们统一管理,因为这个插件可以帮我们将数据保存到localStorage
或sessionStorage
中,这样我们也就无需单独基于localStorage
去封装项目的持久化工具了。
安装pinia-plugin-persistedstate
pnpm i pinia-plugin-persistedstate
注册为pinia
的插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
export const store = createPinia();
store.use(piniaPluginPersistedstate);
对于需要被持久化的store,我们仅需指定persist: true
,这样插件就可以帮我们持久化了,还是以上面的user.ts
这个store为例,具体如下:
import { defineStore } from 'pinia';
// 注册用户模块
export default defineStore('user', {
// 这里用于存放相应模块的状态
state: () => {
return {
username: 'xxx',
// ...
};
},
// ...省略actions和getters
// 仅需设置这个字段,插件就可以帮我们做持久化
persist: true,
});
指定了持久化的选项之后,如果状态有更新,则插件也会帮我们将更新后的数据持久化,并且读取的时候,也会帮我们从localStorage
或sessionStorage
中读取,我们也无需担心刷新页面后数据丢失了。
当然,我们有时候并不需要整个store的数据都持久化,这个时候我们可以通过persist
选项进行更加精细化的控制,单独指定需要持久化的字段。如下所示:
import { defineStore } from 'pinia';
// 注册用户模块
export default defineStore('user', {
// 这里用于存放相应模块的状态
state: () => {
return {
username: 'xxx',
jobInfo: {
company: {},
personal: {},
}
// ...
};
},
// ...省略actions和getters
// 仅需设置这个字段,插件就可以帮我们做持久化
persist: {
// 指定是localStorage还是sessionStorage,默认是local
// storage: window.sessionStorage,
// 更加精细地控制需要持久化的字段
// 像下面就只对jobInfo下的company字段进行持久化
paths: ['jobInfo.company'],
}
});
总结
至此,关于项目接入pinia
就讲完了,其实pinia
的使用非常简单,上面比较关键的是你需要根据你自己项目的模块来划分好store
,这样后续更加易于管理和维护。有什么使用上的问题,欢迎留言,我回尽量解答。
转载自:https://juejin.cn/post/7133979053786316807