【pinia源碼】四肋层、mapHelper API源碼解析

前言

【pinia源碼】系列文章主要分析pinia的實現原理。該系列文章源碼參考pinia v2.0.14

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

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

本篇文章將分析mapHelper API的實現齐媒。

使用

pinia提供了Vuex中的mapStatemapActions等一些輔助函數纷跛。這些函數的定義在packages/pinia/src/mapHelpers.ts中里初。

mapStore

使用mapStore獲取完整的store

import { mapStores } from 'pinia'

const useUserStore = defineStore('user', {
  // ...
})
const useCartStore = defineStore('cart', {
  // ...
})

export default {
  computed: {
    ...mapStores(useCartStore, useUserStore)
  },

  methods: {
    async buyStuff() {
      if (this.userStore.isAuthenticated()) {
        await this.cartStore.buy()
      }
    },
  },
}

mapState忽舟、mapGetters双妨、mapActions

使用mapState,獲取store.statestate.getter叮阅。

mapGettersmapState的別名刁品。

使用mapAction,獲取store.actions浩姥。

export default {
  computed: {
    ...mapState(useCounterStore, {
      n: 'count',
      triple: store => store.n * 3,
      doubleN: 'double'
    })
  },
  created() {
    this.add()
    console.log(this.n) // 2
    console.log(this.doubleN) // 4
  },
  methods: {
    ...mapActions(useCounterStore, {
      add: 'increment',
    })
  }
}

export default {
  computed: {
    ...mapState(useCounterStore, [ 'count', 'double' ])
  },
  created() {
    this.add()
    console.log(this.count) // 2
    console.log(this.double) // 4
  },
  methods: {
    ...mapActions(useCounterStore, [ 'add' ])
  }
}

mapWritableState

mapState相似挑随,與mapState不同的是,通過mapWritableState獲得的數據勒叠,可以直接對其進行修改兜挨。

export default defineComponent({
  name: 'Test',
  computed: {
    ...mapWritableState(useCounterStore, [ 'n' ])
  },
  methods: {
    handleClick() {
      this.n++
    }
  }
})

mapStore源碼

export function mapStores<Stores extends any[]>(
  ...stores: [...Stores]
): _Spread<Stores> {
  // 如果接收的是個數組參數膏孟,進行提示
  if (__DEV__ && Array.isArray(stores[0])) {
    console.warn(
      `[??]: Directly pass all stores to "mapStores()" without putting them in an array:\n` +
        `Replace\n` +
        `\tmapStores([useAuthStore, useCartStore])\n` +
        `with\n` +
        `\tmapStores(useAuthStore, useCartStore)\n` +
        `This will fail in production if not fixed.`
    )
    // 開發(fā)環(huán)境下stores取第一個值
    stores = stores[0]
  }

  // 返回一個對象
  return stores.reduce((reduced, useStore) => {
    // reduced的key值:useStore.$id + mapStoreSuffix(默認Store,可使用setMapStoreSuffix進行修改)
    reduced[useStore.$id + mapStoreSuffix] = function (
      this: ComponentPublicInstance
    ) {
      // 使用useStore獲取store拌汇,在組件中可通過this.$pinia獲取pinia
      return useStore(this.$pinia)
    }
    return reduced
  }, {} as _Spread<Stores>)
}

mapStores可接收多個useStore函數柒桑。

mapStores會對參數進行校驗,如果傳入的第一個參數為數組噪舀,那么在開發(fā)環(huán)境下會進行提示魁淳,并將數組中的第一個值賦給stores,以保證開發(fā)環(huán)境下能夠運行与倡。然后返回一個對象界逛,該對象通過stores.reduce生成,對象的key值是由useStore.$id + mapStoreSuffix組成纺座,對應的value是個函數息拜,在函數中會調用useStore(this.$pinia),返回其結果净响。

mapState少欺、mapGetters源碼

export function mapState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysOrMapper: any
): _MapStateReturn<S, G> | _MapStateObjectReturn<Id, S, G, A> {
  return Array.isArray(keysOrMapper)
    ? keysOrMapper.reduce((reduced, key) => {
        reduced[key] = function (this: ComponentPublicInstance) {
          return useStore(this.$pinia)[key]
        } as () => any
        return reduced
      }, {} as _MapStateReturn<S, G>)
    : Object.keys(keysOrMapper).reduce((reduced, key: string) => {
        reduced[key] = function (this: ComponentPublicInstance) {
          const store = useStore(this.$pinia)
          const storeKey = keysOrMapper[key]
          return typeof storeKey === 'function'
            ? (storeKey as (store: Store<Id, S, G, A>) => any).call(this, store)
            : store[storeKey]
        }
        return reduced
      }, {} as _MapStateObjectReturn<Id, S, G, A>)
}

export const mapGetters = mapState

mapState可以接受兩個參數:useStore(一個useStore函數)、keysOrMapper(一個key列表别惦,或map對象)狈茉。

mapState會返回一個對象,這個對象的key值是通過keysOrMapper獲得的掸掸。如果傳入keysOrMapper是數組氯庆,返回對象的key就是keysOrMapper中的元素,key對應的值是個獲取store[key]的函數扰付。 如果keysOrMapper是個對象堤撵,返回對象的keykeysOrMapper中的keykey對應的值根據keysOrMapper[key]的類型有所區(qū)別羽莺,如果keysOrMapper[key]function实昨,返回結果中對應key的值是一個返回keysOrMapper[key].call(this, store)的函數,否則key對應的是個返回store[keysOrMapper[key]]的函數盐固。

mapGettersmapState礁苗。

mapActions源碼

export function mapActions<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  KeyMapper extends Record<string, keyof A>
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysOrMapper: Array<keyof A> | KeyMapper
): _MapActionsReturn<A> | _MapActionsObjectReturn<A, KeyMapper> {
  return Array.isArray(keysOrMapper)
    ? keysOrMapper.reduce((reduced, key) => {
        reduced[key] = function (
          this: ComponentPublicInstance,
          ...args: any[]
        ) {
          return useStore(this.$pinia)[key](...args)
        }
        return reduced
      }, {} as _MapActionsReturn<A>)
    : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
        reduced[key] = function (
          this: ComponentPublicInstance,
          ...args: any[]
        ) {
          return useStore(this.$pinia)[keysOrMapper[key]](...args)
        }
        return reduced
      }, {} as _MapActionsObjectReturn<A, KeyMapper>)
}

mapActions可以接受兩個參數:useStore(一個useStore函數)燥筷、keysOrMapper(一個key列表积蜻,或map對象)逢唤。

mapActions返回一個對象。對象中的鍵通過keysOrMapper獲得蛔趴,如果keysOrMapper是個數組挑辆,那么key是數組中的元素,對應的值是函數,這個函數返回對應store[key]()的返回值鱼蝉。如果keysOrMapper是個對象洒嗤,那么對象中鍵就是keysOrMapper中的鍵,對應的值是個函數魁亦,這個函數返回store[keysOrMapper[key]]()的返回值渔隶。

mapWritableState源碼

export function mapWritableState<
  Id extends string,
  S extends StateTree,
  G extends _GettersTree<S>,
  A,
  KeyMapper extends Record<string, keyof S>
>(
  useStore: StoreDefinition<Id, S, G, A>,
  keysOrMapper: Array<keyof S> | KeyMapper
): _MapWritableStateReturn<S> | _MapWritableStateObjectReturn<S, KeyMapper> {
  return Array.isArray(keysOrMapper)
    ? keysOrMapper.reduce((reduced, key) => {
        reduced[key] = {
          get(this: ComponentPublicInstance) {
            return useStore(this.$pinia)[key]
          },
          set(this: ComponentPublicInstance, value) {
            return (useStore(this.$pinia)[key] = value as any)
          },
        }
        return reduced
      }, {} as _MapWritableStateReturn<S>)
    : Object.keys(keysOrMapper).reduce((reduced, key: keyof KeyMapper) => {
        reduced[key] = {
          get(this: ComponentPublicInstance) {
            return useStore(this.$pinia)[keysOrMapper[key]]
          },
          set(this: ComponentPublicInstance, value) {
            return (useStore(this.$pinia)[keysOrMapper[key]] = value as any)
          },
        }
        return reduced
      }, {} as _MapWritableStateObjectReturn<S, KeyMapper>)
}

mapWritableState實現過程與mapState相似,只不過mapWritableState返回結果中的value是個對象吉挣,對象中有get派撕、set函數婉弹,通過設置set函數睬魂,用戶就可以修改對應的state

總結

mapStores镀赌、mapState氯哮、mapActions等輔助函數會在內部通過調用useStore(在useStore調用時會傳入this.$piniathis為組件實例商佛,這也是為什么輔助函數不能用在setup中喉钢,因為setup中是無法獲取組件實例)獲取store,然后在store中獲取對應屬性良姆。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末肠虽,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子玛追,更是在濱河造成了極大的恐慌税课,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痊剖,死亡現場離奇詭異韩玩,居然都是意外死亡,警方通過查閱死者的電腦和手機陆馁,發(fā)現死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門找颓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人叮贩,你說我怎么就攤上這事击狮。” “怎么了益老?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵彪蓬,是天一觀的道長。 經常有香客問我杨箭,道長寞焙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮捣郊,結果婚禮上辽狈,老公的妹妹穿的比我還像新娘。我一直安慰自己呛牲,他們只是感情好刮萌,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著娘扩,像睡著了一般着茸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琐旁,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天涮阔,我揣著相機與錄音,去河邊找鬼灰殴。 笑死敬特,一個胖子當著我的面吹牛,可吹牛的內容都是我干的牺陶。 我是一名探鬼主播伟阔,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼掰伸!你這毒婦竟也來了皱炉?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤狮鸭,失蹤者是張志新(化名)和其女友劉穎合搅,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體怕篷,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡历筝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了廊谓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梳猪。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蒸痹,靈堂內的尸體忽然破棺而出春弥,到底是詐尸還是另有隱情,我是刑警寧澤叠荠,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布匿沛,位于F島的核電站,受9級特大地震影響榛鼎,放射性物質發(fā)生泄漏逃呼。R本人自食惡果不足惜鳖孤,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抡笼。 院中可真熱鬧苏揣,春花似錦、人聲如沸推姻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藏古。三九已至增炭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拧晕,已是汗流浹背隙姿。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留防症,地道東北人孟辑。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓哎甲,卻偏偏與公主長得像蔫敲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子炭玫,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容

  • 導航 [深入01] 執(zhí)行上下文[https://juejin.im/post/684490404605093479...
    woow_wu7閱讀 219評論 0 0
  • 特點 1.基于MVVM模式(Model-View-ViewModel)奈嘿,中間通過viewmodel層實現了雙向綁定...
    dawsonenjoy閱讀 826評論 0 1
  • 筆記 腳手架文件結構 ├── node_modules ├── public │ ├── favicon.ico...
    關航_強化班閱讀 242評論 0 0
  • #vue2筆記 ##腳手架文件結構 ├──node_modules ├──public │├──favicon.i...
    Daydream_許多閱讀 421評論 0 0
  • 筆記 腳手架文件結構 關于不同版本的Vue vue.js與vue.runtime.xxx.js的區(qū)別:vue.js...
    jjbnxy閱讀 150評論 0 0