官网解读
https://pinia.vuejs.org/zh/core-concepts/
在这段 Vue3 <script setup> 语法的代码中,有两个关于如何从 useCounterStore 返回的 store 对象中获取状态属性的方式进行了对比。
<script setup>
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
// ❌ 这将不起作用,因为它破坏了响应性
// 这就和直接解构 `props` 一样
const { name, doubleCount } = store
name // 将始终是 "Eduardo"
doubleCount // 将始终是 0
setTimeout(() => {
store.increment()
}, 1000)
// ✅ 这样写是响应式的
// 💡 当然你也可以直接使用 `store.doubleCount`
const doubleValue = computed(() => store.doubleCount)
</script>
第一种方式(不推荐):
const { name, doubleCount } = store
这种方式通过解构赋值直接从 store 对象中提取出 name 和 doubleCount 属性。然而在 Vue3 的响应式系统中,直接通过解构赋值提取的状态属性会失去响应性,也就是说,当 store.name 或 store.doubleCount 的值发生改变时,解构出来的 name 和 doubleCount 不会自动更新。正如注释所说,即使你在 1 秒后调用 store.increment() 改变了 store.count 并进而影响到 store.doubleCount 的值,解构出来的 doubleCount 仍然会保持初始值 0,不会反映出最新的计算结果。
第二种方式(推荐):
const doubleValue = computed(() => store.doubleCount)
这种方式使用了 Vue3 的 computed 声明式依赖追踪功能,doubleValue 是一个计算属性,它依赖于 store.doubleCount。当 store.doubleCount 的值发生变化时,doubleValue 会自动更新。这就是响应式编程的优势,它能确保 UI 总是与数据状态保持同步。
总结:在 Vue3 中,当你需要从 store 中获取并跟踪其状态变化时,推荐使用 computed 函数创建计算属性,而不是通过解构赋值直接提取状态。
从 Store 解构 ,storeToRefs
为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。当你只使用 store 的状态而不调用任何 action 时,它会非常有用。请注意,你可以直接从 store 中解构 action,因为它们也被绑定到 store 上:
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>
在 Vue3 的 Pinia 状态管理库中,storeToRefs 是一个辅助函数,用于将 Pinia Store 中的状态(state)和计算属性(getters)转换为可响应的对象,使得在组件中可以解构出这些属性,并保持其响应性。
当你从 Pinia Store 中获取整个状态对象并在组件中使用时,如果直接解构,那些嵌套的对象属性或计算属性可能会失去响应性。为了避免这个问题,可以使用 storeToRefs 将整个 store 对象转化为一系列可响应的 ref 对象。
例如:
// 定义一个Pinia Store
import { defineStore } from 'pinia';
const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
user: {
name: 'John Doe',
email: 'john@example.com',
},
}),
getters: {
doubleCount: (state) => state.count * 2,
},
});
import { storeToRefs } from 'pinia'
// 在组件中使用store并使用storeToRefs
import { useCounterStore } from '@/stores/counter';
export default {
setup() {
const counterStore = useCounterStore();
const { count, user, doubleCount } = storeToRefs(counterStore);
// 现在count、user和doubleCount都是响应式的
// 可以在模板中直接绑定或在逻辑中使用
return {
count,
user,
doubleCount,
};
},
};
在这个例子中,storeToRefs(counterStore) 返回一个对象,其中的 count、user 和 doubleCount 都是响应式 Ref 对象,当 Store 中的原始状态发生变化时,这些 Ref 对象的值也会随之更新,保证了在组件中使用时的响应性。