Vue3 Pinia
多个组件常常需要共享同一份状态,比如登录用户、购物车、主题偏好,若各自维护一份数据就会互相脱节。Pinia 是 Vue3 官方推荐的状态管理库:它把共享状态收进一个个 store,任何组件都能读取与修改,写法比旧版 Vuex 简洁,对 TypeScript 的支持也更好。
安装与接入
先用包管理器安装 pinia:
npm install pinia
再在入口文件 main.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
用 defineStore 定义一个计数器 store,含 state、getters、actions:
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }), // 状态
getters: { // 派生值,相当于计算属性
double: (state) => state.count * 2,
},
actions: { // 修改状态的方法
increment() {
this.count++
},
},
})
store 的名字 counter 全应用唯一,便于调试工具识别。
在组件中使用
组件中调用 useCounterStore 即可拿到共享 store:
<script setup>
import { useCounterStore } from '../stores/counter'
const store = useCounterStore()
</script>
<template>
<p>当前计数:{{ store.count }},翻倍:{{ store.double }}</p>
<button @click="store.increment()">加一</button>
</template>
页面显示「当前计数:0,翻倍:0」,点击后数字同步变化,任何组件看到的都是同一份状态。
解构与保持响应式
直接解构 state 会丢失响应性,需借助 storeToRefs:
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '../stores/counter'
const store = useCounterStore()
const { count } = storeToRefs(store) // 解构后仍保持响应
</script>
<template>
<p>{{ count }}</p>
</template>
actions 解构则无此顾虑,可直接 const { increment } = store。
组合式风格与持久化
Pinia 也支持组合式风格定义,并在 action 中自行持久化:
// stores/user.js
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', () => {
const token = ref(localStorage.getItem('token') || '')
function login(newToken) {
token.value = newToken
localStorage.setItem('token', newToken) // 写入本地存储
}
return { token, login }
})
刷新页面后从 localStorage 恢复 token,登录态得以保持。
小结
Pinia 用 defineStore 组织共享状态:state 存数据、getters 做派生、actions 改数据。组件间通过 store 单例读写,配合 storeToRefs 与 localStorage,即可满足绝大多数全局状态需求。