3.1 State 的核心概念
- state 工厂函数
- 选项式中返回初始状态的
() => ({...}),每次实例化 store 调用一次。 - 直接修改
- Pinia 允许
store.count++这样直接改,不需要像 Vuex 那样 commit mutation。 - $patch
- store 实例方法,一次性修改多个字段,DevTools 中记录为单次变更,比多次单独赋值更高效。
- $reset
- 把 state 重置回 state 工厂函数返回的初始值(仅选项式 store 内置)。
- $state
- store 的整个 state 对象,可读取也可整体替换:
store.$state = {...}。 - storeToRefs
- 把 store 解构成一组
ref,保留响应式;直接解构会丢失响应式。
3.2 访问 State
const user = useUserStore();
// 读取:直接点属性
console.log(user.name);
console.log(user.age);
在模板中同样直接用:{{ user.name }}。store 本身是响应式代理,读到的永远是最新值。
3.3 直接修改
const counter = useCounterStore();
counter.count++; // ✅ 合法,Pinia 无 mutations
counter.count = 42; // ✅ 直接赋值
counter.list.push(1); // ✅ 数组方法也响应式
为什么可以直接改?
Vuex 要求所有变更走 mutation 是为了"可追踪"。Pinia 靠 Vue 3 的响应式系统 + DevTools 插件即可追踪任意变更,因此取消了 mutation 这层样板代码。
3.4 $patch 批量更新
当要同时改多个字段,用 $patch 合并成一次更新(DevTools 记为一条记录,也减少触发次数):
// 对象形式:浅合并
user.$patch({
name: "张三",
age: 28,
});
// 函数形式:适合数组/复杂逻辑
cart.$patch((state) => {
state.items.push({ id: 1, qty: 2 });
state.total += 20;
});
对象形式 vs 函数形式
对象形式做浅合并,适合替换整字段;涉及数组 push/splice 或依赖当前值的计算时,用函数形式更清晰高效。
3.5 $reset 重置
const form = useFormStore();
form.name = "临时输入";
form.$reset(); // 回到 state() 定义的初始值
组合式 store 没有内置 $reset
$reset 依赖"初始 state 工厂函数",只有选项式 store 才自带。组合式 store 需要自己写一个 reset action,把每个 ref 手动赋回初值。
// 组合式 store 手写 reset
export const useFormStore = defineStore("form", () => {
const name = ref("");
const email = ref("");
function reset() {
name.value = "";
email.value = "";
}
return { name, email, reset };
});
3.6 $state 整体替换
// 读取整个 state
console.log(user.$state);
// 整体替换(常用于 SSR 注水 / 恢复本地缓存)
user.$state = { name: "李四", age: 30, roles: ["admin"] };
3.7 storeToRefs:解构不丢响应式
直接解构 store 会丢失响应式——因为解构出来的是普通值的快照:
// ❌ 错误:name、age 变成一次性快照,不再更新
const { name, age } = useUserStore();
正确做法是用 storeToRefs,它把 state 和 getters 转成 ref,保留响应式:
import { storeToRefs } from "pinia";
const user = useUserStore();
// ✅ name、age、isAdult 都是响应式 ref
const { name, age, isAdult } = storeToRefs(user);
// actions 直接从 store 解构即可(函数无需响应式)
const { setName, fetchUser } = user;
storeToRefs 不含 actions
storeToRefs 只提取 state 和 getters,不会包含 action(函数不需要响应式包装)。action 直接从 store 实例解构或用 store.action() 调用。
3.8 在模板中的对比
<script setup lang="ts">
import { storeToRefs } from "pinia";
import { useUserStore } from "@/stores/user";
const store = useUserStore();
const { name, isAdult } = storeToRefs(store);
</script>
<template>
<!-- ref 在模板里自动解包,直接用 -->
<p>{{ name }} · {{ isAdult ? "成年" : "未成年" }}</p>
<button @click="store.setName('王五')">改名</button>
</template>
3.9 小结与下一步
- state 直接读写即可,无需 mutation;批量改用
$patch。 $reset(仅选项式)回初值,$state可整体替换。- 解构 store 一定要
storeToRefs保响应式;action 直接解构。 - 下一章深入 Getters——派生状态、缓存机制与带参数的 getter。