一、Pinia 是什么?
Pinia 是 Vue 官方推荐的全新状态管理库(可看作 Vuex 的替代品),用于在多个组件间共享数据。
优点包括:
更简单的语法(无 mutations)
支持 TypeScript
响应式更强,性能更好
DevTools 支持出色
二、安装 Pinia
在一个 Vue 3 项目(例如用 Vite 创建的)中运行:
npm install pinia
如果你还没创建项目,可以先这样:
bash
npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
npm install pinia
三、在 main.js 中注册 Pinia
📄 src/main.js
typscript
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
📄 src/stores/counter.js
typescript
import { defineStore } from 'pinia'
// 定义一个 counter store
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
name: 'Victor'
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
},
reset() {
this.count = 0
}
}
})
五、在组件中使用 Store
📄 src/App.vue
typescript
<template>
<div style="padding: 20px">
<h2>Pinia Demo</h2>
<p>Count: {{ counter.count }}</p>
<p>Double: {{ counter.doubleCount }}</p>
<button @click="counter.increment">➕ 加 1</button>
<button @click="counter.reset">🔄 重置</button>
<hr />
<p>用户名: {{ counter.name }}</p>
<input v-model="counter.name" placeholder="修改用户名" />
</div>
</template>
<script setup>
import { useCounterStore } from './stores/counter'
const counter = useCounterStore()
</script>
<style>
button {
margin-right: 8px;
padding: 6px 12px;
}
</style>
六、运行项目
bash
npm run dev
打开浏览器访问控制台提示的地址(默认是 http://localhost:5173/)即可看到效果
🎉
七、Pinia 一般使用场景
场景 示例
✅ 全局状态共享 比如保存登录用户信息、token、主题颜色等
✅ 多组件共享数据 父子组件或兄弟组件共享同一个状态
✅ 请求缓存 请求数据后缓存到 store,下次直接使用
✅ 复杂业务逻辑 将逻辑封装在 actions 里统一管理(类似 Vuex 的 actions)
✅ 组合多个 store 模块 可按业务功能拆分成多个 store 文件
八、扩展:组合多个 store 示例
// src/stores/user.js
typescript
export const useUserStore = defineStore('user', {
state: () => ({ name: 'Guest', token: '' }),
actions: {
login(name) {
this.name = name
this.token = 'mock-token'
}
}
})
```
在组件中使用:
```typescript
<script setup>
import { useUserStore } from './stores/user'
const user = useUserStore()
user.login('Victor')
</script>
```