Pinia 状态管理
概述
Pinia 是 Vue 官方推荐的状态管理库,替代 Vuex。
一、Pinia vs Vuex
| 特性 | Pinia | Vuex 4 |
|---|---|---|
| mutations | 无 | 必需 |
| 模块 | 扁平化 | 嵌套 |
| TypeScript | 原生支持 | 需配置 |
| Composition API | ✅ | 有限 |
| DevTools | ✅ | ✅ |
| 包大小 | ~1KB | ~10KB |
二、定义 Store
Options Store
javascript
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
name: 'Counter'
}),
getters: {
double: (state) => state.count * 2,
// 使用其他 getter
doublePlusOne() {
return this.double + 1;
}
},
actions: {
increment() {
this.count++;
},
async fetchData() {
const res = await fetch('/api/data');
this.count = await res.json();
}
}
});Setup Store
javascript
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => {
// state
const count = ref(0);
// getters
const double = computed(() => count.value * 2);
// actions
function increment() {
count.value++;
}
return { count, double, increment };
});三、使用 Store
vue
<script setup>
import { useCounterStore } from '@/stores/counter';
import { storeToRefs } from 'pinia';
const store = useCounterStore();
// 直接使用
console.log(store.count);
store.increment();
// 解构(失去响应式)
const { count } = store; // ❌
// storeToRefs 保持响应式
const { count, double } = storeToRefs(store); // ✅
// actions 可以直接解构
const { increment } = store; // ✅
</script>
<template>
<p>{{ count }}</p>
<button @click="increment">+1</button>
</template>四、修改 State
javascript
const store = useCounterStore();
// 直接修改
store.count++;
// $patch 批量修改
store.$patch({
count: store.count + 1,
name: 'New Name'
});
// $patch 函数形式
store.$patch((state) => {
state.count++;
state.items.push({ id: 1 });
});
// 替换整个 state
store.$state = { count: 0, name: 'Reset' };
// 重置
store.$reset();五、插件
javascript
import { createPinia } from 'pinia';
const pinia = createPinia();
// 持久化插件
pinia.use(({ store }) => {
// 从 localStorage 恢复
const saved = localStorage.getItem(store.$id);
if (saved) {
store.$patch(JSON.parse(saved));
}
// 订阅变化
store.$subscribe((mutation, state) => {
localStorage.setItem(store.$id, JSON.stringify(state));
});
});
app.use(pinia);六、Store 间通信
javascript
import { useUserStore } from './user';
import { useCartStore } from './cart';
export const useOrderStore = defineStore('order', () => {
const userStore = useUserStore();
const cartStore = useCartStore();
async function createOrder() {
return await api.createOrder({
userId: userStore.id,
items: cartStore.items
});
}
return { createOrder };
});面试高频题
Q1: Pinia 为什么不需要 mutations?
Actions 可以直接修改 state,同步异步统一处理,代码更简洁。DevTools 仍能追踪状态变化。
Q2: 如何实现持久化?
使用 $subscribe 监听变化,存储到 localStorage,初始化时恢复。
Q3: storeToRefs 的作用?
解构 store 时保持响应式,因为 store 是 reactive 对象,直接解构会失去响应式。