Skip to content

Vue 数据缓存方案-Pinia

Pinia 起始于 2019 年 11 月左右的一次实验,其目的是设计一个拥有组合式 API 的 Vue 状态管理库。从那时起,我们就倾向于同时支持 Vue 2 和 Vue 3,并且不强制要求开发者使用组合式 API,我们的初心至今没有改变。除了安装和 SSR 两章之外,其余章节中提到的 API 均支持 Vue 2 和 Vue 3。虽然本文档主要是面向 Vue 3 的用户,但在必要时会标注出 Vue 2 的内容,因此 Vue 2 和 Vue 3 的用户都可以。

1、Pinia 和 Vuex 比较

Vuex 和 Pina 的主要区别在于它们的目的、使用方式、社区支持、数据修改方式、语法和使用、体积以及适用场景。

目的:

  • Vuex 是一个专为 Vue.js 应用提供状态管理的库,旨在提供全面的状态管理解决方案,包括模块化、插件和严格模式等功能。
  • Pina 是一个轻量级的状态管理库,专注于提供一个简单的 API 来管理应用程序的状态,适合初学者和快速开发项目。

使用方式:

  • Vuex 采用全局单例模式,通过一个 store 对象来管理所有的状态,组件通过 store 对象来获取和修改状态。‌
  • Pina 采用了分离模式,每个组件都拥有自己的 store 实例,通过在组件中创建 store 实例来管理状态。

社区支持:

  • Vuex 是 Vue.js 官方出品,社区支持较强,拥有丰富的文档和示例。‌‌
  • Pina 是一个较新的框架,社区支持相对较弱。

数据修改方式:

  • Vuex 有 mutations、getters 和 actions,提供了更多的灵活性。
  • Pina 没有 mutations,只有 state、getters 和 actions,语法上更简单。

体积:

  • Vuex 的体积相对较大,而 Pina 的体积约 1KB,相对较小。

语法和使用:

  • Vuex 的语法相对复杂,需要编写复杂的 action、mutation 和 getter 函数。
  • Pina 的语法更简单,提供了更好的 TypeScript 支持,更容易理解和使用。

适用场景:

  • Vuex 适合复杂的项目和对状态管理有更高要求的开发者。
  • Pina 更适合初学者和快速开发项目。

2、Pinia 状态、动作、和获取器

Pinia 的核心概念包括状态(State)、动作(Actions)和获取器(Getters)。这些概念为你提供了一种组织和管理应用状态的方式。

状态(State): 状态是你在 store 中存储的数据。每个 Pinia store 都有自己的状态,这个状态是一个 JavaScript 对象。你可以在定义 store 时初始化状态:

ts
import { defineStore } from 'pinia';

const useStore = defineStore({
  id: 'myStore',
  state: () => ({
    count: 0,
    user: null,
  }),
});

在这个例子中,count 和 user 就是这个 store 的状态。

动作(Actions): 动作是一种修改 store 状态的方法。在 Pinia 中,你可以在 actions 属性中定义动作:

ts
import { defineStore } from 'pinia';

const useStore = defineStore({
  id: 'myStore',
  state: () => ({
    count: 0,
  }),
  getters: {
    doubleCount() {
      return this.count * 2;
    },
  },
});

在这个例子中,doubleCount 就是一个获取器,它返回 count 的两倍。 通过这些核心概念,Pinia 提供了一种简单而强大的方式来管理和操作你的应用状态。

3、Pinia 基本使用

下面,用一个用户登录存储接口返回 token 的逻辑为例,看一下 Pinia 是如何实现的

1.安装 Pinia

首先,你需要在你的 Vue 项目中安装 Pinia。你可以使用 npm 或 yarn 来安装:

ts
npm install pinia
#或
yarn add pinia

1、main.ts 引入 Pinia

ts
import { creatrePinia } from 'pinia'

const pinia createPinia()

app.use(pinia)

2、创建 Pinia 实例并添加到 Vue 应用

然后,在你的主文件(通常是 main.js 或 main.ts)中,创建一个新的 Pinia 实例,并将其添加到你的 Vue 应用实例中:

ts
import { createPinia } from 'pinia';
import { createApp } from 'vue';

const app = createApp(/* your root component */);
const pinia = createPinia();

app.use(pinia);
app.mount('#app');

3.创建并获取 Store 数据

接下来,你可以开始创建你的 Pinia store。在一个新的文件中,使用 defineStore 函数来定义你的 store:

ts
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment(count: number) {
      this.count = count;
    },
  },
});

然后在你的 Vue 组件中使用 Store,注:只有经过storeToRefs,store数据才会有响应式

ts
<script lang='ts' setup>

import { storeToRefs } from 'pinia';
import { useCounterStore } from '@/stores/counter';

const counter = useCounterStore();

//解构获取【count】
const { count } = storeToRefs(counter)

const dispathStoreCount = (count: number) => {
  //修改store
  counter.increment(count)
}


</script>

在实际开发中,遇到了一个问题:

Login 页面登陆后,接口返回 Token,正常逻辑下,我们会在把 Token 存储进 Pinia 里面,然后在 Axios 请求拦截器里面读取 Pinia 的 Token,但发现读取不到,经过排查,发现在读取 Pinia 数据时,将:

const { token } = userStore()
axios.interceptors.request.use(config => {
   config.headers.token = token;
})

此行代码,写到了 Axios 页面最顶部,此为初始化,经过修改,将 useStore 操作代码,写入请求拦截器内:

axios.interceptors.request.use(config=> {
  const { token } = userStore()
  if(token) {
    config.headers.token = token;
  }
})

这样,就可以解决问题了!

好了,你现在就可以在你的 Vue 项目中使用 Pinia 来管理和操作状态了。更多的信息和高级用法,你可以查阅 Pinia 的官方文档