关于前端:pinia源码二defineStore源码解析

5次阅读

共计 16676 个字符,预计需要花费 42 分钟才能阅读完成。

前言

【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, setup, options, pinia, true)
      : createOptionsStore(hotId, assign({}, options) as any, pinia, true)

    hot._hotUpdate(newStore)

    // cleanup the state properties and the store from the cache
    delete pinia.state.value[hotId]
    pinia._s.delete(hotId)
  }

  if (
    __DEV__ &&
    IS_CLIENT &&
    currentInstance &&
    currentInstance.proxy &&
    !hot
  ) {
    const vm = currentInstance.proxy
    const cache = '_pStores' in vm ? vm._pStores! : (vm._pStores = {})
    cache[id] = store
  }

  // 返回 store
  return store as any
}

useStore接管两个可选参数:piniahotpinia是个 Pinia 的实例,而 hot 只在开发环境下有用,它与模块的热更新无关。

useStore 中会首先获取以后组件实例,如果存在组件实例,应用 inject(piniaSymbol) 获取 pinia(在install 中会进行 provide),并将其设置为activePinia,而后在activePinia._s 中查找是否有被注册为 idstore,如果没有则创立 store,将其注册到activePinia._s 中。最初返回 activePinia._sid对应的store

当初咱们晓得 useStore 函数,最终会返回一个 store。那么这个store 是什么呢?它是如何创立的呢?在 useStore 中依据不同状况中有两中形式来创立 store,别离是:createSetupStorecreateOptionsStore。这两个形式的应用条件是:如果defineStore 第二个参数是个 function 调用createSetupStore,相同调用createOptionsStore

createSetupStore

createSetupStore函数代码过长,这里就不贴残缺代码了。createSetupStore可接管参数如下:

参数 阐明
$id 定义 storeid
setup 一个能够返回 state 的函数
options defineStoreoptions
pinia Pinia实例
hot 是否启用热更新 可选
isOptionsStore 是否应用 options 申明的store 可选

createSetupStore代码有 500 多行,如果从头开始看的话,不容易了解。咱们能够依据 createSetupStore 的用处,从其外围开始看。因为 createSetupStore 是须要创立 store,并将store 注册到 pinia._s 中,所以 createSetupStore 中可能须要创立 store,咱们找到创立store 的中央。

const partialStore = {
  _p: pinia,
  // _s: scope,
  $id,
  $onAction: addSubscription.bind(null, actionSubscriptions),
  $patch,
  $reset,
  $subscribe(callback, options = {}) {
    const removeSubscription = addSubscription(
      subscriptions,
      callback,
      options.detached,
      () => stopWatcher()
    )
    const stopWatcher = scope.run(() =>
      watch(() => pinia.state.value[$id] as UnwrapRef<S>,
        (state) => {if (options.flush === 'sync' ? isSyncListening : isListening) {
            callback(
              {
                storeId: $id,
                type: MutationType.direct,
                events: debuggerEvents as DebuggerEvent,
              },
              state
            )
          }
        },
        assign({}, $subscribeOptions, options)
      )
    )!

    return removeSubscription
  },
  $dispose,
} as _StoreWithState<Id, S, G, A>

if (isVue2) {partialStore._r = false}

const store: Store<Id, S, G, A> = reactive(
  assign(
    __DEV__ && IS_CLIENT
      ? // devtools custom properties
        {_customProperties: markRaw(new Set<string>()),
          _hmrPayload,
        }
      : {},
    partialStore
  )
) as unknown as Store<Id, S, G, A>

pinia._s.set($id, store)

store是用 reactive 包装的一个响应式对象,reactive所包装的对象是由 partialStore 通过 Object.assign 进行复制的。partialStore中定义了很多办法,这些办法都是裸露给用户操作 store 的一些接口,如 $onAction 可设置 actions 的回调、$patch可更新 store 中的 state$dispose 可销毁store

在调用完 pinia._s.set($id, store) 之后,会执行 setup,获取所有的数据。setup 的执行会在创立 pinia 实例时创立的 effectScope 中运行,而且会再独自创立一个effectScope,用来独自执行setup.

const setupStore = pinia._e.run(() => {scope = effectScope()
  return scope.run(() => setup())
})!

而后遍历 setupStore 的属性:如果 propkey 对应的值)为 ref(不为computed)或reactive,则将keyprop同步到 pina.state.value[$id] 中;如果 propfunction,则会应用 wrapAction 包装 prop,并将包装后的办法赋值给setupStore[key],以笼罩之前的值,同时将包装后的办法存入optionsForPlugin.actions 中。

for (const key in setupStore) {const prop = setupStore[key]

  // 如果 prop 是 ref(但不是 computed)或 reactive
  if ((isRef(prop) && !isComputed(prop)) || isReactive(prop)) {if (__DEV__ && hot) {set(hotState.value, key, toRef(setupStore as any, key))
    } else if (!isOptionsStore) {if (initialState && shouldHydrate(prop)) {if (isRef(prop)) {prop.value = initialState[key]
        } else {mergeReactiveObjects(prop, initialState[key])
        }
      }

      // 将对应属性同步至 pinia.state 中
      if (isVue2) {set(pinia.state.value[$id], key, prop)
      } else {pinia.state.value[$id][key] = prop
      }
    }

    if (__DEV__) {_hmrPayload.state.push(key)
    }
  } else if (typeof prop === 'function') { // 如果 prop 是 function
    // 应用 wrapAction 包装 prop,在 wrapAction 会解决 afeterCallback、errorCallback
    const actionValue = __DEV__ && hot ? prop : wrapAction(key, prop)

    // 将 actionsValue 增加到 setupStore 中,笼罩原来的 function
    if (isVue2) {set(setupStore, key, actionValue)
    } else {setupStore[key] = actionValue
    }

    if (__DEV__) {_hmrPayload.actions[key] = prop
    }

    // 将 function 类型的 prop 存入 optionsForPlugin.actions 中
    optionsForPlugin.actions[key] = prop
  } else if (__DEV__) {if (isComputed(prop)) {_hmrPayload.getters[key] = isOptionsStore
        ? // @ts-expect-error
        options.getters[key]
        : prop
      if (IS_CLIENT) {const getters: string[] =
          setupStore._getters || (setupStore._getters = markRaw([]))
        getters.push(key)
      }
    }
  }
}

接下来咱们看下 wrapAction 是如何进行包装 function 类型上的prop

function wrapAction(name: string, action: _Method) {return function (this: any) {setActivePinia(pinia)
    const args = Array.from(arguments)

    const afterCallbackList: Array<(resolvedReturn: any) => any> = []
    const onErrorCallbackList: Array<(error: unknown) => unknown> = []
    function after(callback: _ArrayType<typeof afterCallbackList>) {afterCallbackList.push(callback)
    }
    function onError(callback: _ArrayType<typeof onErrorCallbackList>) {onErrorCallbackList.push(callback)
    }

    triggerSubscriptions(actionSubscriptions, {
      args,
      name,
      store,
      after,
      onError,
    })

    let ret: any
    try {ret = action.apply(this && this.$id === $id ? this : store, args)
    } catch (error) {triggerSubscriptions(onErrorCallbackList, error)
      throw error
    }

    // 如果后果是 promise,在 promise 中触发 afterCallbackList 及 onErrorCallbackList
    if (ret instanceof Promise) {
      return ret
        .then((value) => {triggerSubscriptions(afterCallbackList, value)
          return value
        })
        .catch((error) => {triggerSubscriptions(onErrorCallbackList, error)
          return Promise.reject(error)
        })
    }

    triggerSubscriptions(afterCallbackList, ret)
    return ret
  }
}

wrapAction首先返回一个函数,在这个函数中,首先将 pinia 设置为 activePinia,触发actionSubscriptions 中的函数,而后执行 action 函数,如果执行过程中出错,会执行 onErrorCallbackList 中的 errorCallback,如果没有出错的话,执行afterCallbackList 中的 afterCallback,最初将action 的返回后果return

wrapAction中的 actionSubscriptions 是个什么呢?

其实 actionSubscriptions 中的 callback 就是是通过 store.$onAction 增加的回调函数;在执行 actionSubscriptions 中的 callback 过程中,会将对应 callback 增加到 afterCallbackListonErrorCallbackList中。例如:

store.$onAction(({after, onError, name, store}) => {after((value) => {console.log(value)
  })
  
  onError((error) => {console.log(error)
  })
})

遍历完 setupStore 之后,会将 setupStore 合并至 storestore的原始对对象中,以方便使用 storeToRefs() 检索响应式对象。

if (isVue2) {Object.keys(setupStore).forEach((key) => {
    set(
      store,
      key,
      setupStore[key]
    )
  })
} else {assign(store, setupStore)
  assign(toRaw(store), setupStore)
}

紧接着拦挡 store.$stategetset办法:当调用 store.$state 时,可能从 pinia.state.value 找到对应的 state;当应用store.$state = xxx 去批改值时,则调用 $patch 办法批改值。

Object.defineProperty(store, '$state', {get: () => (__DEV__ && hot ? hotState.value : pinia.state.value[$id]),
  set: (state) => {
    /* istanbul ignore if */
    if (__DEV__ && hot) {throw new Error('cannot set hotState')
    }
    $patch(($state) => {assign($state, state)
    })
  },
})

截止到此,store就筹备结束。如果在 Vue2 环境下,会将 store._r 设置为 true。

if (isVue2) {store._r = true}

接下来就须要调用应用 use 办法注册的plugins

pinia._p.forEach((extender) => {if (__DEV__ && IS_CLIENT) {const extensions = scope.run(() =>
      extender({
        store,
        app: pinia._a,
        pinia,
        options: optionsForPlugin,
      })
    )!
    Object.keys(extensions || {}).forEach((key) =>
      store._customProperties.add(key)
    )
    assign(store, extensions)
  } else {
    // 将 plugin 的后果合并到 store 中
    assign(
      store,
      scope.run(() =>
        extender({
          store,
          app: pinia._a,
          pinia,
          options: optionsForPlugin,
        })
      )!
    )
  }
})

最初返回store

if (
  initialState &&
  isOptionsStore &&
  (options as DefineStoreOptions<Id, S, G, A>).hydrate
) {;(options as DefineStoreOptions<Id, S, G, A>).hydrate!(
    store.$state,
    initialState
  )
}

isListening = true
isSyncListening = true
return store

接下来看下 store 中的几个办法:

$onAction

在每个 action 中增加回调函数。回调接管一个对象参数:该对象蕴含 nameactionkey值)、store(以后 store)、after(增加action 执行完之后的回调)、onError(增加 action 执行过程中的谬误回调)、argsaction的参数)属性。

示例:

// 统计 add action 的调用次数
let count = 0, successCount = 0, failCount = 0
store.$onAction(({name, after, onError}) => {if (name === 'add') {
    count++
    after((resolveValue) => {
      successCount++
      console.log(resolveValue)
    })
  
    onError((error) => {
      failCount++
      console.log(error)
    })
  }
})

$onAction外部通过公布订阅模式实现。在 pinia 中有个专门的订阅模块subscriptions.ts,其中蕴含两个次要办法:addSubscription(增加订阅)、triggerSubscriptions(触发订阅)。

addSubscription可接管四个参数:subscriptions(订阅列表)、callback(增加的订阅函数)、detached(游离的订阅,如果为 false 在组件卸载后,主动移除订阅;如果为true,不会主动移除订阅)、onCleanup(订阅被移除时的回调)

triggerSubscriptions接管两个参数:subscriptions(订阅列表)、argsaction的参数列表)

export function addSubscription<T extends _Method>(subscriptions: T[],
  callback: T,
  detached?: boolean,
  onCleanup: () => void = noop) {subscriptions.push(callback)

  const removeSubscription = () => {const idx = subscriptions.indexOf(callback)
    if (idx > -1) {subscriptions.splice(idx, 1)
      onCleanup()}
  }

  if (!detached && getCurrentInstance()) {onUnmounted(removeSubscription)
  }

  return removeSubscription
}

export function triggerSubscriptions<T extends _Method>(subscriptions: T[],
  ...args: Parameters<T>
) {subscriptions.slice().forEach((callback) => {callback(...args)
  })
}

$onAction通过 addSubscription.bind(null, actionSubscriptions) 实现。

如何触发订阅?

首先在 store 的初始化过程中,会将 action 应用 wrapAction 函数进行包装,wrapAction返回一个函数,在这个函数中会先触发 actionSubscriptions,这个触发过程中会将afterCallbackonErrorCallback 增加到对应列表。而后调用 action,如果调用过程中出错,则触发onErrorCallbackList,否则触发afterCallbackList。如果action 的后果是 Promise 的话,则在 then 中触发 onErrorCallbackList,在catch 中触发 onErrorCallbackList。而后会将包装后的action 笼罩原始 action,这样每次调用action 时就是调用的包装后的action

$patch

应用 $patch 能够更新 state 的值,可进行批量更新。$patch接管一个 partialStateOrMutator 参数,它能够是个对象也能够是个办法。

示例:

store.$patch((state) => {
  state.name = 'xxx'
  state.age = 14
})
// or
store.$patch({
  name: 'xxx',
  age: 14
})

$patch源码:

function $patch(
  partialStateOrMutator:
    | _DeepPartial<UnwrapRef<S>>
    | ((state: UnwrapRef<S>) => void)
): void {
  // 合并的相干信息
  let subscriptionMutation: SubscriptionCallbackMutation<S>
  // 是否触发状态批改后的回调,isListening 代表异步触发,isSyncListening 代表同步触发
  // 此处先敞开回调的触发,避免批改 state 的过程中频繁触发回调
  isListening = isSyncListening = false
  if (__DEV__) {debuggerEvents = []
  }
  // 如果 partialStateOrMutator 是个 function,执行办法,传入以后的 store
  if (typeof partialStateOrMutator === 'function') {partialStateOrMutator(pinia.state.value[$id] as UnwrapRef<S>)
    subscriptionMutation = {
      type: MutationType.patchFunction,
      storeId: $id,
      events: debuggerEvents as DebuggerEvent[],}
  } else { // 如果不是 function,则调用 mergeReactiveObjects 合并 state
    mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator)
    subscriptionMutation = {
      type: MutationType.patchObject,
      payload: partialStateOrMutator,
      storeId: $id,
      events: debuggerEvents as DebuggerEvent[],}
  }
  // 当合并完之后,将 isListening、isSyncListening 设置为 true,意味着能够触发状态扭转后的回调函数了
  const myListenerId = (activeListener = Symbol())
  nextTick().then(() => {if (activeListener === myListenerId) {isListening = true}
  })
  isSyncListening = true
  // 因为在批改 pinia.state.value[$id]的过程中敞开(isSyncListening 与 isListening)了监听,所以须要手动触发订阅列表
  triggerSubscriptions(
    subscriptions,
    subscriptionMutation,
    pinia.state.value[$id] as UnwrapRef<S>
  )
}

$reset

通过构建一个新的 state objectstate重置为初始状态。只在 options 配置下失效。如果是 setup 配置,开发环境下报错。

store.$reset = function $reset() {
  // 从新执行 state,获取一个新的 state
  const newState = state ? state() : {}
  // 通过 $patch,应用 assign 将 newState 合并到 $state 中
  this.$patch(($state) => {assign($state, newState)
  })
}

$subscribe

设置 state 扭转后的回调,返回一个移除回调的函数。可承受两个参数:callback(增加的回调函数)、options:{detached, flush, ...watchOptions}detachedaddSubscription 中的 detachedflush 代表是否同步触发回调,可取值:sync)。

示例:

store.$subribe((mutation: {storeId, type, events}, state) => {console.log(storeId)
  console.log(type)
  console.log(state)
}, {detached: true, flush: 'sync'})

$subscribe源码:

function $subscribe(callback, options = {}) {
  // 将 callback 增加到 subscriptions 中,以便应用 $patch 更新状态时,触发回调
  // 当应用 removeSubscription 移除 callback 时,进行对 pinia.state.value[$id]监听
  const removeSubscription = addSubscription(
    subscriptions,
    callback,
    options.detached,
    () => stopWatcher()
  )
  const stopWatcher = scope.run(() =>
    // 监听 pinia.state.value[$id],以触发 callback,当应用 $patch 更新 state 时,不会进入触发这里的 callback
    watch(() => pinia.state.value[$id] as UnwrapRef<S>,
      (state) => {if (options.flush === 'sync' ? isSyncListening : isListening) {
          callback(
            {
              storeId: $id,
              type: MutationType.direct,
              events: debuggerEvents as DebuggerEvent,
            },
            state
          )
        }
      },
      assign({}, $subscribeOptions, options)
    )
  )!

  return removeSubscription
}

callback 中的第一个参数中有个 type 属性,示意是通过什么形式更新的state,它有三个值:

  1. MutationType.direct:通过 state.name='xxx'/store.$state.name='xxx' 等形式批改
  2. MutationType.patchObject:通过 store.$patch({name: 'xxx'}) 形式批改
  3. MutationType.patchFunction:通过 store.$patch((state) => state.name='xxx') 形式批改

$dispose

销毁store

function $dispose() {
  // 进行监听
  scope.stop()
  // 清空 subscriptions 及 actionSubscriptions
  subscriptions = []
  actionSubscriptions = []
  // 从 pinia._s 中删除 store
  pinia._s.delete($id)
}

createOptionsStore

createOptionsStore可接管参数如下:

参数 阐明
id 定义 storeid
options defineStoreoptions
pinia Pinia实例
hot 是否启用热更新 可选
function createOptionsStore<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A extends _ActionsTree
>(
  id: Id,
  options: DefineStoreOptions<Id, S, G, A>,
  pinia: Pinia,
  hot?: boolean
): Store<Id, S, G, A> {const { state, actions, getters} = options

  const initialState: StateTree | undefined = pinia.state.value[id]

  let store: Store<Id, S, G, A>

  function setup() {// 如果 pinia.state.value[id]不存在,进行初始化
    if (!initialState && (!__DEV__ || !hot)) {if (isVue2) {set(pinia.state.value, id, state ? state() : {})
      } else {pinia.state.value[id] = state ? state() : {}
      }
    }

    // 将 pinia.state.value[id]各属性值转为响应式对象
    const localState =
      __DEV__ && hot
        ? // use ref() to unwrap refs inside state TODO: check if this is still necessary
          toRefs(ref(state ? state() : {}).value)
        : toRefs(pinia.state.value[id])

    // 解决 getters,并将解决后的 getters 和 actions 合并到 localState 中
    return assign(
      localState,
      actions,
      Object.keys(getters || {}).reduce((computedGetters, name) => {computedGetters[name] = markRaw(computed(() => {setActivePinia(pinia)
            const store = pinia._s.get(id)!
            
            if (isVue2 && !store._r) return

            return getters![name].call(store, store)
          })
        )
        return computedGetters
      }, {} as Record<string, ComputedRef>)
    )
  }

  // 利用 createSetupStore 创立 store
  store = createSetupStore(id, setup, options, pinia, hot, true)

  // 重写 store.$reset
  store.$reset = function $reset() {const newState = state ? state() : {}
    this.$patch(($state) => {assign($state, newState)
    })
  }

  return store as any
}

createOptionsStore 中会依据传入参数结构一个 setup 函数,而后通过 createSetupStore 创立一个 store,并重写store.$reset 办法,最初返回store

这个 setup 函数中会将 state() 的返回值赋值给 pinia.state.value[id],而后将pinia.state.value[id] 进行 toRefs,失去localState,最初将解决后的gettersactions都合并到 localState 中,将其返回。对于 getters 的解决:将每个 getter 函数都转成一个计算属性。

总结

defineStore返回一个 useStore 函数,通过执行 useStore 能够获取对应的 store。调用useStore 时咱们并没有传入 id,为什么能精确获取store 呢?这是因为 useStore 是个闭包,在执行 useStore 执行过程中会主动获取id

获取 store 的过程:

  1. 首先获取组件实例
  2. 应用 inject(piniaSymbol) 获取 pinia 实例
  3. 判断 pinia._s 中是否有对应 id 的键,如果有间接取对应的值作为store,如果没有则创立store

store创立流程分两种:setup形式与 options 形式

setup形式:

  1. 首先在 pinia.state.value 中增加键为 $id 的空对象,以便后续赋值
  2. 应用 reactive 申明一个响应式对象store
  3. store 存至 pinia._s
  4. 执行 setup 获取返回值setupStore
  5. 遍历 setupStore 的键值,如果值是 ref(不是computed)或reactive,将键值增加到pinia.state.value[$id] 中;如果值时 function,首先将值应用wrapAction 包装,而后用包装后的 function 替换 setupStore 中对应的值
  6. setupStore 合并到 store
  7. 拦挡 store.$state,使get 操作能够正确获取 pinia.state.value[$id]set 操作应用 this.$patch 更新
  8. 调用 pinia._p 中的扩大函数,扩大store

options形式:

  1. options 中提取stategetteractions
  2. 构建 setup 函数,在 setup 函数中会将 getter 解决成计算属性
  3. 应用 setup 形式创立store
  4. 重写store.$reset
正文完
 0