Pinia: 新一代 Vue 状态管理
Pinia 是 Vue 的官方状态管理库,它被设计为类型安全、模块化且对组合式 API 非常友好。相比于 Vuex,Pinia 的 API 更简洁,模板中访问 store 更直接,并且提供了出色的 TypeScript 支持。
为什么选择 Pinia?
- 更简单的 API:没有 mutations,只有 state、getters 和 actions。Actions 可以是同步或异步的。
- 完整的 TypeScript 支持:无需创建复杂的类型声明即可获得完美的类型推断。
- 模块化设计:每个 store 都是一个独立的模块,可以按需导入和使用。
- 极轻量:体积非常小,只有约 1KB。
- 插件支持:可以通过插件扩展 Pinia 的功能。
安装与配置
首先,安装 Pinia:
bash
npm install pinia然后,在你的 main.js 文件中创建并使用 Pinia 实例:
src/main.js
js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia()) // 创建并使用 Pinia 实例
app.mount('#app')定义 Store
在 Pinia 中,store 是通过 defineStore() 定义的。按照惯例,我们通常在 src/stores/ 目录下创建 store 文件。
src/stores/counter.js
js
import { defineStore } from 'pinia'
// 第一个参数是 store 的唯一 ID
export const useCounterStore = defineStore('counter', {
// state: 返回一个函数,防止在服务端渲染时交叉请求导致数据状态污染
state: () => ({
count: 0,
name: 'Eduardo'
}),
// getters: 类似于组件的 computed 属性
getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlusOne() {
// 可以通过 `this` 访问其他 getter
return this.doubleCount + 1
}
},
// actions: 类似于组件的 methods,可以是异步的
actions: {
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.round(100 * Math.random())
}
}
})在组件中使用 Store
在组件的 <script setup> 中,你可以直接导入并调用 store 的 hook 函数来获取 store 实例。
CounterComponent.vue
vue
<script setup>
import { useCounterStore } from '@/stores/counter'
// 获取 store 实例
const counter = useCounterStore()
//可以直接在模板中使用 store 的 state、getters 和 actions
// counter.count
// counter.doubleCount
// counter.increment()
</script>
<template>
<div>
<p>Count: {{ counter.count }}</p>
<p>Double Count: {{ counter.doubleCount }}</p>
<button @click="counter.increment">Increment</button>
</div>
</template>解构 Store
如果你直接从 Pinia store 中解构,会破坏其响应性。为了解决这个问题,可以使用 storeToRefs。
vue
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
// `storeToRefs` 会将 state 和 getters 转换为响应式的 ref
const { count, doubleCount } = storeToRefs(counter)
const { increment } = counter // actions 可以直接解构
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>Pinia 以其简洁和强大的特性,正在迅速成为 Vue 3 项目中状态管理的首选方案。