Pinia
在组件中使用 Store
掌握在 Vue 组件中读取 Pinia 状态、调用 actions、使用 getters 的正确方式,以及 storeToRefs 的使用场景。
🎯 引言
学会这篇文章,你能掌握在组件中使用 Pinia Store 的正确姿势。重点是:为什么直接解构会丢失响应式,以及 storeToRefs 到底解决了什么问题。
🧱 获取 Store 实例
在 <script setup> 中,调用对应的 use 函数即可:
App.vue
<script setup>
import { useCounterStore } from './stores/counter.js';
const counter = useCounterStore();
</script>
useCounterStore() 返回的是同一个实例。无论在多少个组件中调用,大家操作的都是同一份状态。📖 读取 state 和 getters
拿到实例后,直接通过点语法访问即可:
App.vue
<template>
<p>计数:{{ counter.count }}</p>
<p>双倍:{{ counter.double }}</p>
</template>
<script setup>
import { useCounterStore } from './stores/counter.js';
const counter = useCounterStore();
</script>
🛠 调用 actions
action 的调用和普通方法一样:
App.vue
<template>
<button @click="counter.add">加一</button>
<button @click="counter.addN(5)">加五</button>
</template>
⚡ 为什么直接解构会丢失响应式
很多同学会这样写:
const counter = useCounterStore();
const { count, double } = counter; // ❌ 这样写会有问题
这样解构出来的 count 和 double 只是当时的值。如果 Store 里的 count 后来变了,视图不会更新,因为 count 已经和 Store 断开联系了。
这和 Vue3 的
reactive 解构是一个道理:直接解构响应式对象会丢失响应式。正确做法:storeToRefs
Pinia 提供了 storeToRefs,专门用来解构 Store 中的 state 和 getters,同时保持响应式:
App.vue
<script setup>
import { storeToRefs } from 'pinia';
import { useCounterStore } from './stores/counter.js';
const counter = useCounterStore();
// ✅ 保持响应式
const { count, double } = storeToRefs(counter);
// action 直接解构
const { add, addN } = counter;
</script>
storeToRefs 只对 state 和 getters 有效。actions 不是响应式数据,直接解构即可。💡 对比三种写法
| 写法 | 是否保持响应式 | 适用场景 |
|---|---|---|
counter.count | ✅ | 推荐,最稳妥 |
const { count } = counter | ❌ | 不要这样写 |
const { count } = storeToRefs(counter) | ✅ | 需要解构多个状态时 |
如果你不确定用哪种,直接用
counter.count 这种最原始的方式,永远不会出错。🧾 小节总结
- 在组件中调用
useXxxStore()获取 Store 实例。 - 通过
store.xxx读取 state 和 getters,通过store.action()调用方法。 - 直接解构 Store 会丢失响应式,要用
storeToRefs。 storeToRefs只处理 state 和 getters,actions 直接解构。
❓ 知识问答
Q1:模板中可以直接写 useCounterStore().count 吗?
可以,但每次都调用 use 函数不够优雅。推荐在 <script setup> 中赋值给一个变量,比如 const counter = useCounterStore()。
Q2:storeToRefs 会把整个 Store 都转成 ref 吗?
不会。它只把 state 和 getters 转成 ref,actions 保持原样。
Q3:为什么 action 不需要 storeToRefs?
因为 action 是方法,不是响应式数据。你调用它时只是触发一次函数执行,不需要追踪变化。
Q4:如果我只想解构一个 state,还需要 storeToRefs 吗?
需要。只要解构 state 或 getter,就要用 storeToRefs。
🧪 小练习
下面的组件直接解构了 Store,导致响应式丢失。请改成正确写法:
Counter.vue
<template>
<p>计数:{{ count }}</p>
<p>双倍:{{ double }}</p>
<button @click="add">加一</button>
</template>
<script setup>
import { useCounterStore } from '../stores/counter.js';
const { count, double, add } = useCounterStore(); // 请修改这一行
</script>
🎉 恭喜你掌握了在组件中正确使用 Store 的方法!下一篇我们专门讲 state 的修改方式。
