必须用 storeToRefs 解构 Pinia state,否则会丢失响应性;因为直接解构得到普通 JS 值,无法追踪 reactive 对象内部 ref/computed 的变化。

Pinia 中的 state 解构必须用 storeToRefs,否则会丢失响应性。直接解构 store 实例(比如 const { count } = useCounterStore())得到的是普通 JS 值,后续 state 变化不会触发更新。
为什么不能直接解构?
Pinia 的 store 是 reactive 包裹的对象,但它的属性(如 state 字段)本身可能是 ref、computed 或普通值。Vue 的响应式系统只跟踪 ref、reactive 等特定类型——普通解构会“断开”这层追踪链。
- 错误示例:
const { count } = useCounterStore()→count是静态快照,不响应变化 - 正确逻辑:必须让解构出的变量仍指向原始响应式引用
storeToRefs 的正确用法
storeToRefs() 专门为此设计,它只对 store 内的 ref 和 computed 类型做浅层代理,保留响应链,普通字段(如字符串、数字)则原样返回。
- 基础写法:
const store = useCounterStore(); const { count, name } = storeToRefs(store) - 可链式调用:
const { count } = storeToRefs(useCounterStore()) - 注意:
count此时是 ref,模板中直接写{{ count }}即可自动解包;在 JS 中读取需count.value,赋值也用count.value = 5
哪些属性需要 storeToRefs?
仅当 state 中定义了 ref() 或 computed() 时才必须用它。纯对象属性(如 state: () => ({ userName: '张三' }))本身不具响应性,修改它们不会触发更新——这类字段应改用 ref 包裹。
- 推荐 state 写法:
state: () => ({ userName: ref('张三'), list: ref([]) }) - 这样
storeToRefs(store)才能正确代理userName和list - 如果只是
userName: '张三',解构后userName就是普通字符串,改了也不更新视图
配合 setup script 的常见模式
在 <script setup></script> 中,通常把 storeToRefs 和状态使用封装在一起,保持逻辑内聚。
- 导入:
import { useCounterStore } from '@/stores/counter'; import { storeToRefs } from 'pinia' - 使用:
const counterStore = useCounterStore(); const { count } = storeToRefs(counterStore) - 模板中:
<span>{{ count }}</span>(自动解包) - JS 中修改:
count.value++或调用counterStore.increment()


















