likes
comments
collection
share

【大厂企业级项目架构】之状态管理

作者站长头像
站长
· 阅读数 32

这是大厂企业级项目架构系列的第六篇,这系列的文章如下:

本篇文章比较短,因为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帮我们统一管理,因为这个插件可以帮我们将数据保存到localStoragesessionStorage中,这样我们也就无需单独基于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,
});

指定了持久化的选项之后,如果状态有更新,则插件也会帮我们将更新后的数据持久化,并且读取的时候,也会帮我们从localStoragesessionStorage中读取,我们也无需担心刷新页面后数据丢失了。

当然,我们有时候并不需要整个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
评论
请登录