Pinia——Vue的Store状态管理库
一、Store 是什么?
Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,state、getter 和 action,我们可以假设这些概念相当于组件中的 data
、 computed
和 methods
。
二、Pinia 是什么?
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。
三、安装+全局引入
1、安装pinia
npm install pinia
2、创建 Pinia 实例
在项目入口文件(如 main.js
)中初始化并挂载 Pinia:
// main.js
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.mount('#app');
注意:需确保所有 Store 的使用在 Pinia 实例挂载之后
四、定义Store-defineStore()
Store 是用 defineStore()
定义的,它的第一个参数要求是一个独一无二的名字:
import { defineStore } from 'pinia'// 返回值最好以 `use` 开头且以 `Store` 结尾。
// (比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useUserStore = defineStore('user', {// 其他配置...
})
返回值(useUserStore):最好以 `use` 开头且以 `Store` 结尾
第一个参数(user):也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。
第二个参数:可【Setup函数】或【Option对象】
1、【Option 对象】——推荐使用
传入一个带有 state
、actions
与 getters
属性的 Option 对象
export const useCounterStore = defineStore('counter', {state: () => ({ count: 0,name: 'Eduardo'}),getters: {doubleCount: (state) => state.count * 2,},actions: {increment() {this.count++},},
})
简单理解:
state
是 store 的数据 (data
)
getters
是 store 的计算属性 (computed
)
actions
是方法 (methods
)优点:简单,容易使用
2、【Setup函数】
也可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
export const useCounterStore = defineStore('counter', () => {const count = ref(0)const name=ref("Eduardo")const doubleCount = computed(() => count.value * 2)function increment() {count.value++}return { count, doubleCount, increment }
})
在 Setup Store 中:
ref()
就是state
属性computed()
就是getters
function()
就是actions
- 注意:必须在 setup store 中返回
state
的所有属性。
优点:更灵活
可以在 store 内创建侦听器
可以依赖于全局提供的属性,比如路由。
任何应用层面提供的属性都可以在 store 中使用
inject()
访问,就像在组件中一样
五、基础示例
1、创建Store:
// stores/counter.jsimport { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', {state: () => {return { count: 0.name: 'Eduardo',isAdmin: true,items: [],hasChanged: true,}},// 也可以这样定义// state: () => ({ count: 0 })actions: {increment() {this.count++},},})return { count, increment }
})
2、使用Store --useCounterStore():
<script setup>import { useCounterStore } from '@/stores/counter'const counter = useCounterStore()counter.count++// 自动补全! ✨counter.$patch({ count: counter.count + 1 })// 或使用 action 代替counter.increment()//从Store解构
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script><template><!-- 直接从 store 中访问 state --><div>Current Count: {{ counter.count }}</div>
</template>
store
是一个用 reactive
包装的对象,就像 setup
中的 props
一样,我们不能对它进行解构:
六、State
state 都是你的 store 的核心。在 Pinia 中,state 被定义为一个返回初始状态的函数。
1、定义
import { defineStore } from 'pinia'const useUserStore = defineStore('user', {// 为了完整类型推理,推荐使用箭头函数state: () => {return {// 所有这些属性都将自动推断出它们的类型count: 0,name: 'Eduardo',isAdmin: true,items: [],hasChanged: true,}},
})
2、使用
<script setup>import { useUserStore } from '@/stores/counter'const store = useUserStore()//访问store.count++//重置-将state重置为初始值store.$reset()//变更多个属性store.$patch({count: store.count + 1,name: "aaa",
})//另一种变更方式store.$patch((state) => {state.items.push({ name: 'shoes', quantity: 1 })state.hasChanged = true
})
</script>
注意:
使用Setup stores中,重置需要创建自己的$reset()方法,例如
export const useCounterStore = defineStore('counter', () => {const count = ref(0)function $reset() {count.value = 0}return { count, $reset }
})
七、Getter
1、定义
Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore()
中的 getters
属性来定义它们。推荐使用箭头函数,并且它将接收 state
作为第一个参数:
export const useCounterStore = defineStore('counter', {state: () => ({count: 0,}),getters: {doubleCount: (state) => state.count * 2,},
})
大多数时候,getter 仅依赖 state。不过,有时它们也可能会使用其他 getter(自行学习)
2、使用
<script setup>
import { useCounterStore } from './counterStore'
const store = useCounterStore()
</script>
<template><p>Double count is {{ store.doubleCount }}</p>
</template>
八、Action
1、定义
Action 相当于组件中的 method。它们可以通过 defineStore()
中的 actions
属性来定义
export const useCounterStore = defineStore('main', {state: () => ({count: 0,}),actions: {increment() {this.count++},randomizeCounter() {this.count = Math.round(100 * Math.random())},},
})
action 可通过 this
访问整个 store 实例
2、使用
Action 可以像函数或者通常意义上的方法一样被调用:
<script setup>const store = useCounterStore()
// 将 action 作为 store 的方法进行调用
store.randomizeCounter()</script><template><!-- 即使在模板中也可以 --><button @click="store.randomizeCounter()">Randomize</button></template>
其他用法:
访问其他store的action
订阅action——
store.$onAction()
九、配置状态持久化——persist
过这个设置,你可以指定哪些状态属性需要被保存到 localStorage
或 sessionStorage
中,从而在页面刷新或重新加载后仍然保持这些数据。
使用方法
- 安装插件:
npm install pinia-plugin-persistedstate
- 引入并使用插件: 在 Pinia 实例中添加插件:
import './assets/main.css'
import { createApp } from 'vue'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
import {createPinia} from "pinia";import App from './App.vue'
import router from './router'const store = createPinia()
store.use(piniaPluginPersistedstate);createApp(App).use(store).use(router).mount('#app')
- 配置 Store 的持久化路径: 在定义 store 时,通过
persist.paths
指定需要持久化的属性:
import { defineStore } from 'pinia';export const useUserStore = defineStore('user', {state: () => ({loginType: '',clientId: '',// 其他不需要持久化的状态...}),persist: {paths: ['loginType', 'clientId'], // 只保存这两个属性},
});
这样,只有 loginType
和 clientId
这两个属性会被自动同步到浏览器的存储中,在页面刷新后依然可用。
高级配置
除了 paths
,还可以进一步自定义持久化行为:
- storage:选择
localStorage
或sessionStorage
。
persist: {storage: sessionStorage,paths: ['loginType', 'clientId'],}
- serializer:自定义数据的序列化与反序列化方式。
persist: {serializer: {serialize: (value) => JSON.stringify(value),deserialize: (value) => JSON.parse(value),},paths: ['loginType', 'clientId'],}
配置选项说明
- key: 存储数据的键名,默认为 store 的 id。
- storage: 数据存储位置,默认为
localStorage
,也可改为sessionStorage
。 - paths: 指定哪些状态路径需要持久化,如
['token']
。 - serializer: 自定义序列化和反序列化方法,支持加密等需求。
- beforeRestore 和 afterRestore: 分别在恢复数据前后触发的钩子函数。
详情可见Pinia官网:Pinia | The intuitive store for Vue.js
我只是学习路上记录了一下~