Vue组件通信原理剖析(二)全局状态管理Vuex

  • 需要对外暴露一个对象,这样就可以满足new Vuex.Store()

// src/index.js

import { Store, install } from ‘./store’

import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from ‘./helpers’

export default {

Store,

install,

version: ‘VERSION’,

mapState,

mapMutations,

mapGetters,

mapActions,

createNamespacedHelpers

}

  • 其次是定义store,并且实现vue的Install方法

// src/store.js

let Vue // bind on install

export class Store {

}

// 实现的Install方法

export function install (_Vue) {

if (Vue && _Vue === Vue) {

if (process.env.NODE_ENV !== ‘production’) {

console.error(

‘[vuex] already installed. Vue.use(Vuex) should be called only once.’

)

}

return

}

Vue = _Vue

applyMixin(Vue)

}

问题2:state的数据响应式

看懂了Vuex的入口定义,下面我们就针对store的定义来一探究竟,先看看state的实现

// src/store.js

export class Store {

constructor(options = {}) {

// strict mode

this.strict = strict

const state = this._modules.root.state

// initialize the store vm, which is responsible for the reactivity

// (also registers _wrappedGetters as computed properties)

// 看上面的注释可以得知,resetStoreVM就是初始化store中负责响应式的vm的方法,而且还注册所有的gettersz作为vm的计算属性

resetStoreVM(this, state)

}

}

我们来看看resetStoreVM的具体实现

// src/store.js

function resetStoreVM (store, state, hot) {

const oldVm = store._vm

// bind store public getters

store.getters = {}

// reset local getters cache

store._makeLocalGettersCache = Object.create(null)

const wrappedGetters = store._wrappedGetters

const computed = {}

// 这里是实现getters的派生

forEachValue(wrappedGetters, (fn, key) => {

// use computed to leverage its lazy-caching mechanism

// direct inline function use will lead to closure preserving oldVm.

// using partial to return function with only arguments preserved in closure environment.

computed[key] = partial(fn, store)

Object.defineProperty(store.getters, key, {

get: () => store._vm[key],

enumerable: true // for local getters

})

})

// use a Vue instance to store the state tree

// suppress warnings just in case the user has added

// some funky global mixins

// 这是是通过new一个Vue实例,并将state作为实例的datas属性,那他自然而然就具有了响应式

const silent = Vue.config.silent

Vue.config.silent = true

store._vm = new Vue({

data: {

$$state: state

},

computed

})

Vue.config.silent = silent

// enable strict mode for new vm

if (store.strict) {

enableStrictMode(store)

}

if (oldVm) {

if (hot) {

// dispatch changes in all subscribed watchers

// to force getter re-evaluation for hot reloading.

store._withCommit(() => {

oldVm._data.$$state = null

})

}

Vue.nextTick(() => oldVm.$destroy())

}

}

问题3:getters实现state中的数据的派生

关于getters的实现,我们在上面也做了相应的解释,实际上就是将getters的方法包装一层后,收集到computed对象中,并使用Object.defineProperty注册store.getters,使得每次取值时,从store._vm中取。

关键的步骤就是创建一个Vue的实例

store._vm = new Vue({

data: {

$$state: state // 这是store中的所有state

},

computed // 这是store中的所有getters

})

问题4:mutations中同步commit

// src/store.js

// store的构造函数

constructor(options = {}) {

// 首先在构造方法中,把store中的commit和dispatch绑定到自己的实例上,

// 为什么要这么做呢?

// 是因为在commit或者dispatch时,尤其是dispatch,执行function时会调用实例this,而方法体内的this是具有作用域属性的,所以如果要保证每次this都代表store实例,就需要重新绑定一下。

const store = this

const { dispatch, commit } = this

this.dispatch = function boundDispatch (type, payload) {

return dispatch.call(store, type, payload)

}

this.commit = function boundCommit (type, payload, options) {

return commit.call(store, type, payload, options)

}

}

// commit 的实现

commit (_type, _payload, _options) {

// check object-style commit

const {

type,

payload,

options

} = unifyObjectStyle(_type, _payload, _options)

const mutation = { type, payload }

// 通过传入的类型,查找到mutations中的对应的入口函数

const entry = this._mutations[type]

// 这里是执行的主方法,通过遍历入口函数,并传参执行

this._withCommit(() => {

entry.forEach(function commitIterator (handler) {

handler(payload)

})

})

}

问题5:actions中的异步dispatch

上面说了在构造store时绑定dispatch的原因,下面我们就继续看看dispatch的具体实现。

// src/store.js

// dispatch 的实现

dispatch (_type, _payload) {

// check object-style dispatch

const {

type,

payload

} = unifyObjectStyle(_type, _payload)

const action = { type, payload }

// 同样的道理,通过type获取actions中的入口函数

const entry = this._actions[type]

······

// 由于action是异步函数的集合,这里就用到了Promise.all,来合并多个promise方法并执行

const result = entry.length > 1

? Promise.all(entry.map(handler => handler(payload)))
entry 0

return result.then(res => {

try {

this._actionSubscribers

.filter(sub => sub.after)

.forEach(sub => sub.after(action, this.state))

} catch (e) {

if (process.env.NODE_ENV !== ‘production’) {

console.warn([vuex] error in after action subscribers: )

console.error(e)

}

}

return res

})

}

到这里,我们就把整个store中状态存储和状态变更的流程系统的串联了一遍,让我们对Vuex内部的机智有个简单的认识,最后我们根据我们对Vuex的理解来实现一个简单的Vuex。

// store.js

let Vue

// 定义store类

class Store{

constructor(options = {}) {

this.$options = options

this._mutations = options.mutations

this._actions = options.actions

this._wrappedGetters = options.getters

// 定义computed

const computed = {}

this.getters = {}

const store = this

Object.keys(this._wrappedGetters).forEach(key => {

// 获取用户定义的getters

const fn = store._wrappedGetters[key]

// 转换为computed可以使用无参数形式

computed[key] = function() {

return fn(store.state)

}

// 为getters定义只读属性

Object.defineProperty(store.getters, key {

get:() => store._vm[key]

})

})

// state的响应式实现

this._vm = new Vue({

data: {

// 加两个$,Vue不做代理

$$state: options.state

},

computed // 添加计算属性

})

this.commit = this.commit.bind(this)

this.dispatch = this.dispatch.bind(this)

}

// 存取器,获取store.state ,只通过get形式获取,而不是直接this.xxx, 达到对state

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
,18年进入阿里一直到现在。**

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-iRT6GDAh-1715700629625)]

[外链图片转存中…(img-soWDxAHB-1715700629626)]

[外链图片转存中…(img-dxVt0wE0-1715700629626)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值