pinia 中 storeToRefs源码解析
export function storeToRefs<SS extends StoreGeneric>(
store: SS
): ToRefs<
StoreState<SS> & StoreGetters<SS> & PiniaCustomStateProperties<StoreState<SS>>
> {
// See https://github.com/vuejs/pinia/issues/852
// 直接使用toRefs()更容易,即使它包含了更多内容
if (isVue2) {
// 如果是vue2,直接返回store的所有ref引用,尽管这样可能会包括一些方法
return toRefs(store)
} else {
// 在非vue2环境中,仅过滤store中的ref或reactive对象
// 获取store的原始对象,即从可能的响应式代理中获得原始数据
store = toRaw(store)
// 创建一个对象,用于存储转换后的ref引用
const refs = {} as ToRefs<
StoreState<SS> &
StoreGetters<SS> &
PiniaCustomStateProperties<StoreState<SS>>
>
// 遍历store中的所有属性
for (const key in store) {
const value = store[key]
// 检查属性值是否是ref或reactive,即它们是否是响应式的
if (isRef(value) || isReactive(value)) {
// 将响应式的属性转换为一个独立的ref引用,并将其添加到refs对象中
refs[key] = toRef(store, key)
}
}
// 返回包含所有转换后ref引用的对象
return refs
}
}
这个函数storeToRefs
接收一个StoreGeneric的泛型SS扩展的store参数。它返回一个ToRefs
类型的对象,这个对象包含了StoreState<SS>
、StoreGetters<SS>
以及PiniaCustomStateProperties<StoreState<SS>>
的类型。这意味着返回的对象里面会包含store的state、getters以及一些Pinia自定义的状态属性的响应式引用。 这个函数会根据当前Vue的版本来采取不同的行为:
- 如果是Vue 2版本,它会直接返回
toRefs(store)
的结果,即使这样可能包括一些不是状态或getters的方法或其他属性。 - 如果不是Vue 2版本,那么它首先将store转为其原始对象,避免处理Vue的响应式代理对象,然后针对store中的每一个属性值进行检查,仅当这个属性值是响应式的(ref或reactive)时,才使用
toRef
将其转换为一个响应式的ref,并最终返回一个包含所有这些ref的对象。
pinia 使用记录
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useUser } from '@/store/user.js'
const userStore = useUser()
console.log(userStore)
// 如果直接解构出数据,这个数据不是响应式的。如果想要变成响应式的,需要调用【storeToRefs】方法
// ### storeToRefs 和 toRefs 都可以将状态对象转换为具有 .value 的 ref 对象集合。
// 区别:!!!!!!!【【【【【 storeToRefs 是针对 pinia 的 store 对象】】】】】
// 而 toRefs 是 Vue 3 中的通用函数,用于处理任意的响应式对象。
// 所以+++++ 【【 使用 storeToRefs 需要引入 pinia,而 toRefs 可以在Vue 3中直接使用】】】++++++
console.log(userStore.userName, '=====userStore 中的名称')
const { changeNameAsync, info2 } = userStore
const { userName, info } = storeToRefs(userStore) // state he getter 这样处理 才会是响应式的
console.log('======userStore ====', userStore)
console.log('======storeToRefs(userStore) ====', storeToRefs(userStore))
// import { useStore } from '@/store'
// const store = useStore()
// console.log(store)
const changeName = (val) => {
userName.value = val // 单个数据修改
// 批量修改state
// userStore.$patch({
// userName: '张三'
// })
}
</script>
<template>
<div>pinia的使用{{ userStore.userName }}</div>
<div>读取state中的值userName: {{ userName }}</div>
<div>读取getter中的值info: {{ info }}</div>
<div>读取getter中的值info----2 没有调用storeToRefs方法的 : {{ info2 }}</div>
<div @click="changeName('sophia')">更改userName的值为sophia</div>
<div @click="userStore.changeNameAsync('新宇')">调用sction 方法</div>
<div @click="changeNameAsync('新宇2')">调用sction 方法2</div>
</template>
import { defineStore } from 'pinia'
import { useGoods } from './goods.js'
export const useUser = defineStore({
id: 'user',
state: () => {
return {
count: 1,
userName: '潇潇洒洒'
}
},
getters: {
info: (state) => {
// 获取goods模块的store
const goodsStore = useGoods()
return state.userName + '买了' + goodsStore.newIphone
},
info2: (state) => {
// 获取goods模块的store
const goodsStore = useGoods()
return state.userName + '买了' + goodsStore.newIphone
}
},
actions: {
// 这里的方法要写成普通函数,因为里面需要通过this去访问state里面的数据
changeNameAsync(newName) {
setTimeout(() => {
// actions里面可以访问state
this.userName = newName
}, 1000)
}
}
})
1、 如果直接解构出数据,这个数据不是响应式的。如果想要变成响应式的,需要调用【storeToRefs】方法
2、storeToRefs 和 toRefs 都可以将状态对象转换为具有 .value 的 ref 对象集合。
3、区别:【【【【【 storeToRefs 是针对 pinia 的 store 对象】】】】】
4、而 toRefs 是 Vue 3 中的通用函数,用于处理任意的响应式对象。
5、所以【 使用 storeToRefs 需要引入 pinia,而 toRefs 可以在Vue 3中直接使用】
6、action中的方法不在storeToRefs 处理后的对象内;没有storeToRefs处理的state 和getter 不是响应式的。
const { changeNameAsync, info2 } = userStore