Vuex3.x 源码学习

Vuex 是专为 Vue.js 应用程序开发的状态管理模式,它可以实现我们 Vue 中跨级组件的通信,也可以存储全局共享的状态;它主要通过 state 来定义状态,通过 commitdispatch 来同步或异步修改状态;

图片

一、基础用法
  • 安装依赖:npm install vuex
  • 编写 store 实例并导出;
// src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    // 全局状态
    state: {
        count: 1
    },
    // 存储同步修改 state 中变量的方法
    mutations: {},
    // 存储异步操作的方法
    actions: {},
    // 相当于 computed 的作用
    getters: {},
    // 子模块
    modules: {}
})
  • 在 main.js 中进行注册;
// main.js
import Vue from 'vue'
import store from './store/index.js'
import App from './App.vue'
new Vue({
    store,
    render: h => h(App)
}).$mount('#app')
  • 在页面中使用:

(1)在 computed 属性中进行定义

<script>
export default {
   computed: {
       count() {
           return this.$store.state.count
       }
   } 
}
</script>

(2)通过 mapState 获取

<script>
import { ...mapState } from 'vuex'
export default {
   computed: {
       // 方式一
       ...mapState([
           'count'
       ])
       // 方式二
       //...mapState({
       //    count: state => state.count
       //})
       // 方式三: 命名空间
       //...mapState('xxx', [
       //	   'count'
       //])
   }
}
</script>
二、基本原理

了解完基础用法之后,接下来通过源码来理解其内部实现;

  • 首先是通过 Vuex.use(Vuex) 来进行插件安装,那我们知道 Vue.use 是通过调用插件的 install 方法来安装,那么 Vuex 的实现需要有一个 install 方法;
  • 实例化 Vuex 是 new Vuex.Store({}),则需要有一个 Store类或方法;
  • mapStatemapMutationsmapActionsmapGetters 实现;
1、install 方法
// src/store.js
export function install(_Vue) {
    if (Vue && _Vue === Vue) {
        if (__DEV__) {
            console.error(
                '[vuex] already installed. Vue.use(Vuex) should be called only once.'
            )
        }
        return
    }
    Vue = _Vue
    // 注入的核心
    applyMixin(Vue)
}
// src/mixin.js
export default function (Vue) {
    const version = Number(Vue.version.split('.')[0])
    // 版本判断,如果是 2.x,则在全局 beforeCreate 生命周期中插入
    if (version >= 2) {
        Vue.mixin({ beforeCreate: vuexInit })
    } else {
        const _init = Vue.prototype._init
        Vue.prototype._init = function (options = {}) {
            options.init = options.init
                ? [vuexInit].concat(options.init)
            : vuexInit
            _init.call(this, options)
        }
    }
    function vuexInit () {
        const options = this.$options
        // 根实例注入 $store
        if (options.store) {
            this.$store = typeof options.store === 'function'
               	? options.store()
            	: options.store
        } else if (options.parent && options.parent.$store) {
            // 从父节点获取 store 实例
            this.$store = options.parent.$store
        }
    }
}

可以看到 install 做的事情比较简单,install 方法主要将 $store 注入到组件或页面中,2.x 版本及以上是通过 beforeCreate 注入,其他的则通过在 init 方法中注入,类似于 $mount 方法;

2、Store 类

Store 类主要是对传入的 options 进行处理,包括模块收集、安装模块、处理父子模块之间的关系等,可以参考简略版vuex 的代码,需要注意的是命名空间的处理,调用孙子模块需要确保父模块的路径名称正确

3、mapState、mapMutations、mapActions、mapGetters 的实现

mapState、mapMutations、mapActions、mapGetters 工具方法可以帮助我们一次性获取多个 store 中的变量和方法,内部实现也比较简单,主要分几个步骤:

  • 对用户传入的参数进行处理 normalizeNamespace
  • 对用户传入的参数进行格式化 normalizeMap,然后循环遍历取值赋值给返回结果;
  • 如果有命名空间,则根据命名空间获取相应的模块 getModuleByNamespace,返回该模块的数据;
  • 不同类型的实现可以参考本文第二点代码仓库的代码,位置在 helper.js 文件;
// 将数据转化为 map, 格式为 { key, val }
// (1) 参数为数组: mapState(['xxx'])
// (2) 参数为对象: mapState({ xxx: store => store.state.xxx })
function normalizeMap(map) {
    return Array.isArray(map)
        ? map.map(key => ({ key, val: key }))
        : Object.keys(map).map(key => ({ key, val: map[key] }))
}

// 对参数和 namespace 进行处理
// (1) 不带命名空间: mapState([])
// (2) 带命名空间: mapState('namespace', []), 对命名空间进行处理,保持 namespace/ 的格式
function normalizeNamespace(fn) {
    return (namespace, map) => {
        if (typeof namespace !== 'string') {
            map = namespace
            namespace = ''
        } else if (namespace.charAt(namespace.length - 1) !== '/') {
            namespace += '/'
        }
        return fn(namespace, map)
    }
}

// 根据命名空间获取相应的模块
function getModuleByNamespace(store, helper, namespace) {
    const module = store._modulesNameSpaceMap[namespace]

    if (!module) {
        console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)
    }

    return module
}
三、总结

Vuex 是专门为 Vue 提供状态管理的插件,注册之后可以在全局访问到 $store 实例,同时也提供一些 api 来辅助我们获取实例中的状态和状态变更的方法,其内部实现主要是根据传入的 options 来进行模块间关系的处理,也可以通过命名空间来快速访问状态,方便我们在日常开发使用;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在Vuex中,可以使用mapState辅助函数来帮助我们生成计算属性。mapState函数可以接收一个对象或一个字符串数组作为参数。如果传入一个对象,对象的键将作为计算属性的名称,值将作为计算属性的值。如果传入一个字符串数组,数组中的每个字符串将被当作计算属性的名称,并且会与state的子节点名称相匹配。\[1\]这样可以避免在组件中重复声明多个计算属性。例如,可以使用mapState来获取store中的count状态: computed: mapState({ count: state => state.count }) 或者可以使用字符串数组的方式来获取count状态: computed: mapState(\['count'\]) 在这两种方式中,count将作为计算属性的名称,并且会与state的子节点名称相匹配。\[2\]这样就可以在组件中直接使用this.count来获取count状态的值。同时,mapState函数返回的是一个对象,该对象包含了计算属性的定义。\[1\]所以在computed选项中,可以直接将mapState函数的返回值赋值给computed属性。\[2\]这样就可以在组件中使用计算属性来获取store中的状态值。 #### 引用[.reference_title] - *1* *2* [Vuex中的 mapState](https://blog.csdn.net/m0_64707449/article/details/127495971)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Vuex中mapState](https://blog.csdn.net/qq_54250695/article/details/123938509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值