聊聊Vuex原理

本文深入探讨Vuex的原理,从Vue组件开发的角度出发,介绍了$store的注入、响应式状态、mutations与actions的处理,以及namespaced的使用。通过源码分析,揭示了Vuex如何实现状态管理,包括数据响应、发布订阅模式的应用,以及辅助方法的使用。理解Vuex的内部机制有助于更好地在实践中应用。
摘要由CSDN通过智能技术生成

背景

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。如果你已经灵活运用,但是依然好奇它底层实现逻辑,不妨一探究竟。

Vue 组件开发

我们知道开发 Vue 插件,安装的时候需要执行 Vue.use(Vuex)

import Vue from 'vue'
import Vuex from '../vuex'

Vue.use(Vuex)

通过查看 Vue API Vue-use 开发文档,我们知道安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。该方法需要在调用 new Vue() 之前被调用。当 install 方法被同一个插件多次调用,插件将只会被安装一次。

为了更好了的去理解源码意思,这里写了一个简单的测试实例。

测试实例代码
import Vue from 'vue'
import Vuex from '../vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  plugins: [],
  state: {
    time: 1,
    userInfo: {
      avatar: '',
      account_name: '',
      name: ''
    },
  },
  getters: {
    getTime (state) {
      console.log('1212',state)
      return state.time
    }
  },
  mutations: {
    updateTime(state, payload){
      state.time = payload
    }
  },
  actions: {
    operateGrou({ commit }) {
      // commit('updateTime', 100)
      return Promise.resolve().then(()=>{
        return {
          rows: [1,2,3]
        }
      })
    }
  },
  modules: {
    report: {
      namespaced: true,
      state: {
        title: '',
      },
      getters: {
        getTitle (state) {
          return state.title
        }
      },
      mutations: {
        updateTitle(state, payload){
          state.title = payload
        }
      },
      actions: {
        operateGrou({ commit }) {
          commit('updateTitle', 100)
          return Promise.resolve().then(()=>{
            return {
              rows: [1,2,2,3]
            }
          })
        }
      },
      modules: {
        reportChild: {
          namespaced: true,
          state: {
            titleChild: '',
          },
          mutations: {
            updateTitle(state, payload){
              state.title = payload
            }
          },
          actions: {
            operateGrou({ commit }) {
              commit('updateTitle', 100)
              return Promise.resolve().then(()=>{
                return {
                  rows: [1,2,2,3]
                }
              })
            }
          },
        }
      }
    },
    part: {
      namespaced: true,
      state: {
        title: '',
      },
      mutations: {
        updateTitle(state, payload){
          state.title = payload
        },
        updateTitle1(state, payload){
          state.title = payload
        }
      },
      actions: {
        operateGrou({ commit }) {
          commit('updateTitle', 100)
          return Promise.resolve().then(()=>{
            return {
              rows: [1,2,2,3]
            }
          })
        }
      },
      modules: {
        partChild: {
          namespaced: true,
          state: {
            titleChild: '',
          },
          getters: {
            getTitleChild (state) {
              return state.titleChild
            }
          },
          mutations: {
            updateTitle(state, payload){
              state.titleChild = payload
            }
          },
          actions: {
            operateGrou({ commit }) {
              commit('updateTitle', 1000)
              return Promise.resolve().then(()=>{
                return {
                  rows: [1,2,2,3]
                }
              })
            }
          },
          modules: {
            partChildChild: {
              namespaced: true,
              state: {
                titleChild: '',
              },
              getters: {
                getTitleChild (state) {
                  return state.titleChild
                }
              },
              mutations: {
                updateTitle(state, payload){
                  state.titleChild = payload
                }
              },
              actions: {
                operateGrou({ commit }) {
                  commit('updateTitle', 1000)
                  return Promise.resolve().then(()=>{
                    return {
                      rows: [1,2,2,3]
                    }
                  })
                }
              },
            }
          }
        }
      }
    }
  }
})
Graphviz 父子结点关系图

用 Graphviz 图来表示一下父子节点的关系,方便理解

组件开发第一步 install & mixin

在调用 Vuex 的时候会找其 install 方法,并把组件实例传递到 install 方法的参数中。

let Vue;
class Store {
   

}

const install = _Vue => {
   
    Vue = _Vue;
    Vue.mixin({
   
        beforeCreate(){
   
           console.log(this.$options.name);
        }
    })
};

export default {
   
    Store,
    install
}

到这里说一下 Vuex 实现的思想,在 Vuex 的 install 方法中,可以获取到 Vue 实例。
我们在每个 Vue 实例上添加 $store 属性,可以让每个属性访问到 Vuex 数据信息;
我们在每个 Vue 实例的 data 属性上添加上 state,这样 state 就是响应式的;
收集我们传入 new Vuex.Store(options) 即 options 中所有的 mutaions、actions、getters;
接着当我们 dispatch 的时候去匹配到 Store 类中存放的 actions 方法,然后去执行;
当我们 commit 的时候去匹配到 Store 类中存放的 mutations 方法,然后去执行;
这其实就是一个发布订阅模式,先存起来,后边用到再取再执行。好了解这些,我们开始真正的源码分析;参考vue实战视频讲解:进入学习

Vue 实例注入 $store

为了更好理解,我们打印出 Vue 实例,可以看到注入了 $store,见下图。

image.png

具体实现关键点

const install = (_Vue) => {
   
  Vue = _Vue
  Vue.mixin({
   
    beforeCreate(){
   
      // 我们可以看下面 main.js 默认只有我们的根实例上有 store,故 this.$options.store 有值是根结点
      if(this.$options.store) {
    
        this.$store = this.$options.store // 根结点赋值
      } else {
   
        this.$store = this.$parent && this.$parent.$store // 每个实例都会有父亲。故一层层给实例赋值
      }
    }
  })
}
  • main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
   
  store,
  render: h => h(App)
}).$mount('#app')

$store.state 响应式

响应式核心就是挂载到实例 data 上,让 Vue 内部运用 Object.defineProperty 实现响应式。

class Store{
   
  constructor (options) {
    // 我们知道 options 是用户传入 new Vuex.Store(options) 参数
    this.vm = new Vue({
   
      data: {
   
        state: options.state
      }
    })
  }
}

$store.mutations & commit

来看下 用户传入的 mutations 变成了什么,数据采用 最上面的测试实例代码。
我们可以看到 mutations 是一个对象,里面放了函数名,值是数组,将相同函数名对应的函数存放到数组中。

image.png

mutations
  • 实际上就是收集用户传入的 mutations, 放到一个对象中。
 const setMoutations = (data, path = []) => {
   
    const mutations = data.mutations
    Object.keys(mutations).map(item => {
   
      this.mutations[item] = this.mutations[item] || [] // 之前的旧值
      this.mutations[item].push(mutations[item]) // 存起来
    })
    const otherModules = data.modules || {
   } // 有子 modules 则递归
    if (Object.keys(otherModules).length > 0){
   
      Object.keys(otherModules).map
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值