【pinia源码】二、defineStore源码解析

本文详细分析了Pinia库中`defineStore`的实现原理,包括`createSetupStore`和`createOptionsStore`的创建过程。`defineStore`根据传入参数的不同,创建setup风格或options风格的store。在`useStore`中,根据组件实例获取或注入Pinia,并在Pinia的订阅列表中注册store。文章还探讨了`$onAction`、`$patch`、`$reset`、`$subscribe`等关键方法的实现,以及store的创建和销毁过程。

【pinia源码】系列文章

  1. 【pinia源码】一、createPinia源码解析
  2. 【pinia源码】二、defineStore源码解析
  3. 【pinia源码】三、storeToRefs源码解析
  4. 【pinia源码】四、mapHelper API源码解析


前言

【pinia源码】系列文章主要分析pinia的实现原理。该系列文章源码参考pinia v2.0.14

源码地址:https://github.com/vuejs/pinia

官方文档:https://pinia.vuejs.org

本篇文章将分析defineStore的实现。

使用

通过defineStore定义一个store

const useUserStore = defineStore('counter', {
   
   
  state: () => ({
   
   
    count: 0
  }),
  actions: {
   
   
    increment() {
   
   
      this.count++
    }
  }
})

// or
const useUserStore = defineStore({
   
   
  id: 'counter',
  state: () => ({
   
   
    count: 0
  }),
  actions: {
   
   
    increment() {
   
   
      this.count++
    }
  }
})

// or
const useUserStore = defineStore('counter', () => {
   
   
  const count = ref(0)
  
  function increment() {
   
   
    count.value++
  }
  return {
   
    count, increment }
})

defineStore

export function defineStore(
  idOrOptions: any,
  setup?: any,
  setupOptions?: any
): StoreDefinition {
   
   
  let id: string
  let options:
    | DefineStoreOptions<
        string,
        StateTree,
        _GettersTree<StateTree>,
        _ActionsTree
      >
    | DefineSetupStoreOptions<
        string,
        StateTree,
        _GettersTree<StateTree>,
        _ActionsTree
      >

  const isSetupStore = typeof setup === 'function'
  if (typeof idOrOptions === 'string') {
   
   
    id = idOrOptions
    options = isSetupStore ? setupOptions : setup
  } else {
   
   
    options = idOrOptions
    id = idOrOptions.id
  }

  function useStore(pinia?: Pinia | null, hot?: StoreGeneric): StoreGeneric {
   
    // ... }

  useStore.$id = id

  return useStore
}

defineStore函数可以接收三个参数:idOrOptionssetupsetOptions,后两个参数为可选参数。下面是三个defineStore的函数类型定义。

export function defineStore<
  Id extends string,
  S extends StateTree = {
     
     },
  G extends _GettersTree<S> = {
     
     },
  A /* extends ActionsTree */ = {
     
     }
>(
  id: Id,
  options: Omit<DefineStoreOptions<Id, S, G, A>, 'id'>
): StoreDefinition<Id, S, G, A>

export function defineStore<
  Id extends string,
  S extends StateTree = {
     
     },
  G extends _GettersTree<S> = {
     
     },
  A /* extends ActionsTree */ = {
     
     }
  >(options: DefineStoreOptions<Id, S, G, A>): StoreDefinition<Id, S, G, A>

export function defineStore<Id extends string, SS>(
  id: Id,
  storeSetup: () => SS,
  options?: DefineSetupStoreOptions<
    Id,
    _ExtractStateFromSetupStore<SS>,
    _ExtractGettersFromSetupStore<SS>,
    _ExtractActionsFromSetupStore<SS>
    >
): StoreDefinition<
  Id,
  _ExtractStateFromSetupStore<SS>,
  _ExtractGettersFromSetupStore<SS>,
  _ExtractActionsFromSetupStore<SS>
  >

首先在defineStore中声明了三个变量:idoptionsisSetupStore,其中id为定义的store的唯一idoptions为定义store时的optionsisSetupStore代表传入的setup是不是个函数。

然后根据传入的idOrOptions的类型,为idotions赋值。紧接着声明了一个useStore函数,并将id赋给它,然后将其return。截止到此,我们知道defineStore会返回一个函数,那么这个函数具体是做什么的呢?我们继续看useStore的实现。

useStore

function useStore(pinia?: Pinia | null, hot?: StoreGeneric): StoreGeneric {
   
   
  // 获取当前实例
  const currentInstance = getCurrentInstance()
  // 测试环境下,忽略提供的参数,因为总是能使用getActivePinia()获取pinia实例
  // 非测试环境下,如果未传入pinia,则会从组件中使用inject获取pinia
  pinia =
    (__TEST__ && activePinia && activePinia._testing ? null : pinia) ||
    (currentInstance && inject(piniaSymbol))
  // 设置激活的pinia
  if (pinia) setActivePinia(pinia)

  // 如果没有activePinia,那么可能没有install pinia,开发环境下进行提示
  if (__DEV__ && !activePinia) {
   
   
    throw new Error(
      `[🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia?\n` +
        `\tconst pinia = createPinia()\n` +
        `\tapp.use(pinia)\n` +
        `This will fail in production.`
    )
  }

  // 设置pinia为激活的pinia
  pinia = activePinia!

  // 从pina._s中查找id否注册过,如果没有被注册,创建一个store并注册在pinia._s中
  if (!pinia._s.has(id)) {
   
   
    if (isSetupStore) {
   
   
      createSetupStore(id, setup, options, pinia)
    } else {
   
   
      createOptionsStore(id, options as any, pinia)
    }

    if (__DEV__) {
   
   
      useStore._pinia = pinia
    }
  }

  // 从pinia._s中获取id对应的store
  const store: StoreGeneric = pinia._s.get(id)!

  if (__DEV__ && hot) {
   
   
    const hotId = '__hot:' + id
    const newStore = isSetupStore
      ? createSetupStore(hotId
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MAXLZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值