官网解读
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对象的值也会随之更新,保证了在组件中使用时的响应性。