Pinia 是 Vue.js 官方推荐的新一代状态管理库,它提供了非常简洁和直观的 API,可以极大地提高我们管理应用状态的效率。本文将深入介绍 Pinia 的各种高级用法,内容涵盖:
Pinia 的优势
相比 Vuex,Pinia 有以下优点:
- 更贴合 Vue 3 的 Composition API 风格,学习成本更低
- 不需要区分 Mutation 和 Action,统一使用 Actions 操作状态
- 支持 TypeScript,可以充分利用 TS 的静态类型系统
- 模块化管理 States,每个模块是一个 Store
- 直观的 Devtools,可以看到每个 State 的变化
创建 Pinia
在 main.js 中导入 createPinia 并使用:
import { createApp } from 'vue' import { createPinia } from 'pinia' const pinia = createPinia() const app = createApp(App) app.use(pinia)
可以通过 app.config.globalProperties.$pinia
访问 Pinia 实例。
Option Store
与 Vue 的选项式 API 类似,我们也可以传入一个带有
state
、actions
与getters
属性的 Option 对象(废弃了Mutations)
使用 defineStore
API 定义 Store:
import { defineStore } from 'pinia' export const useMainStore = defineStore('main', { // state state: () => { return { counter: 0 } }, // getters getters: { doubleCount(state) { return state.counter * 2 } }, // actions actions: { increment() { this.counter++ } } })
- 接收唯一 ID 作为第一个参数
- state、getters、actions 定义方式与 Vue 组件类似
- 可以直接通过
this
访问状态
Pinia 提供多种选项配置 Store:
state
定义响应式状态:
state: () => { return { count: 0 } }
必须是一个返回状态对象的函数。
getters
定义 getter 计算属性:
getters: { double(state) { return state.count * 2 } }
getter 可以接收参数:
getters: { getMessage(state) { return (name = 'Vue') => `Hello ${name}` } }
actions
定义方法修改状态:
actions: { increment(amount = 1) { this.count += amount } }
actions 支持同步和异步操作。
persist
配置数据持久化,需要使用插件:
persist: { enabled: true, strategies: [ { key: 'my_store', storage: localStorage, }, ] }
使用 Store
通过 useXxxStore()
获取 Store 实例:
import { useMainStore } from '@/stores/main' export default { setup() { const main = useMainStore() main.increment() } }
读取状态、调用 actions 同 Vue 组件。
读取状态
// 直接读取 const count = main.count // 通过计算属性 const double = computed(() => main.doubleCount) // 通过 storeToRefs const { count } = storeToRefs(main)
调用 Actions
main.increment() const message = main.getMessage('Vue')
多个 Store
可以拆分多个 Store 管理不同模块状态:
stores |- user.js |- product.js
单独导出每个 Store 并在组件中使用:
import { useUserStore } from '@/stores/user' import { useProductStore } from '@/stores/product' export default { setup() { // ... } }
Store 可以互相引用:
// userStore.js import { useProductStore } from './product' export const useUserStore = defineStore({ // 可以直接使用 productStore })
Setup Store
个人比较倾向这种语法
也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
export const useCounterStore = defineStore('counter', () => { const count = ref(0) function increment() { count.value++ } return { count, increment } })
在 Setup Store 中:
ref()
就是state
属性computed()
就是getters
function()
就是actions
Setup store 比 Option Store 带来了更多的灵活性,因为你可以在一个 store 内创建侦听器,并自由地使用任何组合式函数。不过,请记住,使用组合式函数会让 SSR 变得更加复杂。
数据持久化
Pinia 默认状态不持久化,可以通过插件实现持久化:
npm install pinia-plugin-persistedstate
import persistedState from 'pinia-plugin-persistedstate' const pinia = createPinia() pinia.use(persistedState)
在 Store 中配置 persist
:
export const useUserStore = defineStore({ persist: { enabled: true } })
配置 storage
指定存储位置:
persist: { storage: sessionStorage }