好的!这份笔记专为你整理,涵盖了 Pinia 的核心知识点、实战写法和避坑指南。内容尽量精简结构化,方便你直接复制保存,随时查阅。
📦 Pinia 核心知识笔记(Vue 3 专用)
一句话概括 :Pinia 是 Vue 的官方状态管理库,用于在不同组件之间共享响应式数据(相当于前端内存里的全局数据库)。
1. 核心概念(三大支柱)
| 概念 | 作用 | 类比 Java / 后端 |
|---|---|---|
| State(状态) | 存储共享的数据 | 类的成员变量(属性) |
| Getters(计算属性) | 基于 State 派生出新数据(类似 Vue 的 computed) |
类的 getter 方法(如 getFullName) |
| Actions(动作) | 修改 State 的方法(支持异步) | 类的 setter 或 service 方法 |
2. 如何定义一个 Store(两种写法)
✅ 写法一:选项式(Options Store)------ 适合传统习惯
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
name: 'Vue'
}),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++; // 注意:在 actions 里用 this 访问 state
},
async fetchCount() {
// 支持异步
const res = await api.getCount();
this.count = res.data;
}
}
});
✅ 写法二:组合式 API(Setup Store)------ 推荐写法(你目前学的)
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useUserStore = defineStore('user', () => {
// 1. State(用 ref 定义响应式数据)
const list = ref<User[]>([]);
const loading = ref(false);
// 2. Getters(用 computed 定义)
const totalCount = computed(() => list.value.length);
// 3. Actions(用普通函数定义)
const setList = (newList: User[]) => {
list.value = newList;
};
// 4. 将需要暴露的内容返回出去
return { list, loading, totalCount, setList };
});
区别 :选项式用
this,组合式用ref/computed并直接return。组合式更灵活,且 TypeScript 类型推导更好。
3. 在组件中使用 Store(⚠️ 重点:响应性丢失问题)
❌ 错误写法(解构会丢失响应性)
const { list, setList } = useUserStore();
// list 变成了普通值,修改后页面不会更新!
✅ 正确写法 1:直接使用 store 对象
const store = useUserStore();
// 模板中直接用 store.list,方法用 store.setList
✅ 正确写法 2:使用 storeToRefs 解构(保持响应性)
import { storeToRefs } from 'pinia';
const store = useUserStore();
// 只能解构 state 和 getters(用 storeToRefs)
const { list, totalCount } = storeToRefs(store);
// actions 可以直接解构(不需要包起来)
const { setList } = store;
// 此时 list 和 totalCount 依然是响应式的!
4. 修改 State 的四种方式(由简到繁)
| 方式 | 代码示例 | 适用场景 |
|---|---|---|
| 1. 直接修改 | store.list = [...] |
简单赋值 |
| 2. 通过 Actions | store.setList([...]) |
推荐! 逻辑复用,便于调试 |
3. $patch 批量修改 |
store.$patch({ count: 1, name: 'hi' }) |
同时改多个字段 |
4. $patch 函数式修改 |
store.$patch((state) => { state.count++ }) |
复杂逻辑批量改 |
最佳实践 :所有修改尽量封装在
actions里,避免业务逻辑散落在各个组件中。
5. Getters(派生状态)详解
// 在 store 里定义
const filteredList = computed(() => {
return list.value.filter(item => item.name.includes('张'));
});
// 在组件里使用(配合 storeToRefs 解构或直接 store.filteredList)
const { filteredList } = storeToRefs(store);
特点:Getter 会根据依赖自动缓存,只有依赖变化时才重新计算。
6. Actions(处理异步请求)------ 配合你的 Axios
// store 里定义
const fetchUsers = async () => {
loading.value = true;
try {
const res = await getUserList(); // 你封装的 Axios 方法
list.value = res;
} catch (error) {
console.error('加载失败', error);
} finally {
loading.value = false;
}
};
// 在组件里调用
await store.fetchUsers();
7. 跨 Store 通信(一个 Store 引用另一个)
import { useUserStore } from './user';
export const useOrderStore = defineStore('order', () => {
const userStore = useUserStore(); // 直接引入其他 Store
const currentUser = computed(() => {
// 拿到用户列表里的第一个
return userStore.list[0];
});
return { currentUser };
});
8. 数据持久化(刷新页面数据丢失怎么办?)
Pinia 默认存在内存中,页面刷新就没了。通常配合插件 pinia-plugin-persistedstate:
npm i pinia-plugin-persistedstate
// main.ts 中配置
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
// 在 store 中开启持久化
export const useUserStore = defineStore('user', () => {
// ...
}, {
persist: true // 自动存 localStorage
});
9. 在 Vue Router(路由守卫)中使用 Pinia
注意:在路由守卫中不能直接用 useUserStore()(因为 Pinia 还没激活)。要在 router 文件里这样写:
// router/index.ts
router.beforeEach((to) => {
// 确保 Pinia 已激活(Vue 应用已挂载)
const userStore = useUserStore();
if (to.meta.requiresAuth && !userStore.isLoggedIn) {
return '/login';
}
});
10. Vue Devtools 调试
Pinia 默认集成 Vue Devtools,在浏览器插件中可以:
- 查看所有 Store 的当前 State。
- 回放 Actions 的历史记录(时间旅行调试)。
🚀 速查速记口诀
- 定义仓库 :
defineStore('id', () => { ... }) - 定义数据 :
ref()/reactive()包起来 - 定义计算 :
computed()返回派生值 - 定义方法 :普通函数,操作
value - 暴露出去 :
return { data, method } - 组件使用 :
const store = useXxxStore() - 解构数据 :必须用
storeToRefs(store),方法不用 - 改数据:优先用 Actions,别到处直接改
这份笔记覆盖了 Pinia 95% 的日常开发场景。刚开始学可以先照着"组合式 API"的模板写,遇到复杂需求再回来看高级用法。祝学习顺利!😊