pinia 使用 and storeToRefs 源码解析

109 阅读3分钟

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的版本来采取不同的行为:

  1. 如果是Vue 2版本,它会直接返回toRefs(store)的结果,即使这样可能包括一些不是状态或getters的方法或其他属性。
  2. 如果不是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

截屏2024-01-09 11.23.10.png

截屏2024-01-09 11.23.42.png