Pinia 是 Vue.js 生态中备受推崇的状态管理库,它提供了简洁、直观且类型安全的状态管理方案,逐渐成为 Vue 应用开发的首选。本文将基于官方文档,全面介绍 Pinia 的核心概念与使用方式。
一、Pinia 环境搭建
安装与配置
要在 Vue 项目中使用 Pinia,只需两步:
- 使用 npm 安装 Pinia:
bash
复制下载
npm install pinia
- 在 main.ts 中创建并注册 Pinia:
typescript
复制下载
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia) // 注册 Pinia 插件
app.mount('#app')
完成配置后,Vue Devtools 中将出现 Pinia 选项,方便进行状态调试。
二、核心概念:Store 的创建与使用
Store 是 Pinia 的核心,它是一个保存状态和业务逻辑的实体。每个组件都可以读取和写入 Store,类似于组件中的 data、computed 和 methods 的组合。
创建 Store
Pinia 提供了两种 Store 创建方式:选项式和组合式。
1. 选项式 Store(推荐初学者)
typescript
复制下载
// src/store/count.ts
import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
// 状态(相当于 data)
state: () => ({
sum: 6
}),
// 计算属性(相当于 computed)
getters: {},
// 方法(相当于 methods)
actions: {}
})
// src/store/talk.ts
export const useTalkStore = defineStore('talk', {
state: () => ({
talkList: [
{ id: 'yuysada01', content: '你今天有点怪,哪里怪?怪好看的!' },
{ id: 'yuysada02', content: '草莓、蓝莓、蔓越莓,你想我了没?' },
{ id: 'yuysada03', content: '心里给你留了一块地,我的死心塌地' }
]
})
})
2. 组合式 Store(Vue 3 风格)
typescript
复制下载
import { defineStore } from 'pinia'
import { reactive } from 'vue'
export const useTalkStore = defineStore('talk', () => {
const talkList = reactive(
JSON.parse(localStorage.getItem('talkList') as string) || []
)
async function getATalk() {
// 异步逻辑
}
return { talkList, getATalk }
})
在组件中使用 Store
vue
复制下载
<template>
<h2>当前求和为:{{ countStore.sum }}</h2>
<ul>
<li v-for="talk in talkStore.talkList" :key="talk.id">
{{ talk.content }}
</li>
</ul>
</template>
<script setup lang="ts">
import { useCountStore } from '@/store/count'
import { useTalkStore } from '@/store/talk'
const countStore = useCountStore()
const talkStore = useTalkStore()
</script>
三、状态修改的三种方式
Pinia 提供了灵活的状态修改方式:
1. 直接修改(简单场景)
typescript
复制下载
countStore.sum = 666
2. 批量修改(性能优化)
typescript
复制下载
countStore.$patch({
sum: 999,
school: 'atguigu'
})
3. 通过 Action 修改(业务逻辑封装)
typescript
复制下载
// 在 Store 中定义 actions
export const useCountStore = defineStore('count', {
state: () => ({ sum: 0 }),
actions: {
increment(value: number) {
if (this.sum < 10) {
this.sum += value
}
},
decrement(value: number) {
if (this.sum > 1) {
this.sum -= value
}
}
}
})
// 在组件中调用
const countStore = useCountStore()
countStore.increment(5)
四、响应式辅助工具
storeToRefs
将 Store 中的状态转换为 ref 对象,保持响应式的同时方便解构:
vue
复制下载
<template>
<h2>当前求和为:{{ sum }}</h2>
</template>
<script setup lang="ts">
import { useCountStore } from '@/store/count'
import { storeToRefs } from 'pinia'
const countStore = useCountStore()
const { sum } = storeToRefs(countStore) // 保持响应式
</script>
五、Getters:计算状态
Getters 用于派生状态,当 state 需要处理后再使用时特别有用:
typescript
复制下载
export const useCountStore = defineStore('count', {
state: () => ({
sum: 1,
school: 'atguigu'
}),
getters: {
// 使用 state 参数
bigSum: (state): number => state.sum * 10,
// 使用 this 访问
upperSchool(): string {
return this.school.toUpperCase()
}
}
})
// 组件中使用
const { bigSum, upperSchool } = storeToRefs(countStore)
六、状态监听与持久化
$subscribe 监听状态变化
typescript
复制下载
talkStore.$subscribe((mutate, state) => {
console.log('状态变化:', mutate, state)
// 状态持久化
localStorage.setItem('talk', JSON.stringify(talkList.value))
})
七、组合式 API 实践
组合式 Store 写法更加灵活,适合复杂场景:
typescript
复制下载
export const useTalkStore = defineStore('talk', () => {
const talkList = reactive(
JSON.parse(localStorage.getItem('talkList') as string) || []
)
async function getATalk() {
const { data: { content: title } } = await axios.get(
'https://api.uomg.com/api/rand.qinghua?format=json'
)
const obj = { id: nanoid(), title }
talkList.unshift(obj)
}
return { talkList, getATalk }
})
总结
Pinia 以其简洁的 API、优秀的 TypeScript 支持和灵活的架构设计,为 Vue 应用提供了强大的状态管理能力。无论是简单的状态共享还是复杂的业务逻辑封装,Pinia 都能提供优雅的解决方案。通过本文的介绍,相信你已经掌握了 Pinia 的核心用法,可以开始在项目中实践这一现代化的状态管理方案了。
核心优势:
- 直观的 API 设计
- 完整的 TypeScript 支持
- 模块化结构
- 轻量级且高性能
- 与 Vue Devtools 完美集成