vue全家桶之-1-vuex源码分析-及实现

简介: 有了前面的router铺垫 接下来学习会更easy

1.前言


有了前面的router铺垫 接下来学习会更easy


2. vuex简单使用 + 分析


vuex安装

index.js


mutations: {
   add(state){
     state.count++
   }
 },
 actions: {
   add({commit}){
     setTimeout(() => {
       commit("add")
     }, 1000);
   }
 },

思考上面的 参数state 上下文 commit怎么来的

App.vue


<p @click="$store.commit('add')">{{$store.state.count}}</p>
    <p @click="$store.dispatch('add')">asy:{{$store.state.count}}</p>



3.基本结构


复制store目录 命名我们自己的 zstore

main.js修改引用


// import store from './store'
import store from './zstore'

创建我们自己的 zvuex.js

zstore/index.js修改引用


import Vuex from './zvuex'



4. 需求分析


1 实现Store类

1.维持一个响应式状态 state

2.实现commit

3.实现 dispatch

4.getters

2 挂载 $store


5.  基础结构


需要导出一个 store

因为new Vuex.Store({}) 使用的时候 有Store


class Store{
    constructor(options){}
    commit(){}
    dispatch(){}
}
function install(_Vue,options){}
export default {Store,install}



6. 注册 $store


参考 $router的写法

主要是混入


Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })



7. 保存数据信息


关键是这个数据是 响应式的

Vue.util.defineReactive(this,'state',{})

这次我们借力 ,使用 Vue 来创建响应式数据


class Store{
    constructor(options){
         console.log(" options:",options);
        console.log(" this:",this);
        // 保存数据
        this.$options = options
        // Vue.util.defineReactive(this,'state',{})
      this.state =  new Vue({
            data(){
                return options.state
            }
        })
    }
    commit(){}
    dispatch(){}
}

options 就是挂载上去的 store信息

也就是 state mutations

2W7}F@~V1~SA1RJ4YF5{027.png

this.state的数据就是响应式的 用到这个数据的组件就会随着这个组件的变化而更新


8. 界面查看效果


点击也生效了

V~[]E9}J%2MRRA02ANQ{8_J.png



9. 不是标准写法


因为用户可以直接操纵 state了 ,需要通过 commit

核心是我们不希望用户简单轻松的就访问到数据,而且轻易的修改了这个数据,这样会破坏数据流,也不方便追踪数据变化


class Store {
    constructor(options) {
        // 保存数据
        this.$options = options
        // Vue.util.defineReactive(this,'state',{})
        // 用户访问 name 并且轻松修改了 这不是我们想看到的
        // this._vm.name ="修改了"
        this._vm = new Vue({
            data() {
                return {
                    // 不做代理
                    $$state:options.state,
                    // name:"yzs"
                }
            }
        })     
    }
    get state(){
        // 这里的访问就比较深了 ,就是不想用户简单的就访问了我们的数据
        return this._vm._data.$$state
    }
    set state(z){
        console.error("请使用 replaceState 重置state");
    }
    commit() { }
    dispatch() { }
}



10. commit


参考 commit的用法 想象它的实现方式

用法 store.commit("add",2)

payload载荷 简单理解为参数,其实也就是对接受者有用的数据


commit(type,payload) { 
        //根据type 从用户配置的 mutaions中 获取函数
      const entry =  this._mutations[type]
      if(!entry){
        return console.error("unknow mutaion")
      }
      entry(this.state,payload)
    }



11. dispatch


比葫芦画瓢 应该能写出来


dispatch(type,payload) { 
        const entry =  this._actions[type]
        if(!entry){
          return console.error("unknow actions")
        }
        // dispatch 的上下文是 state实例 
        entry(this,payload)
    }

注意 这个 dispatch的参数

通常我们在使用时候 称呼为 ctx上下文 ,那到底是啥呢

常规写法


actions: {
    add(ctx){
      setTimeout(() => {
        ctx.commit("add")
      }, 1000);
    }
  },

结构写法


actions: {
    add({commit,state,mutations,modules}){
      setTimeout(() => {
        commit("add")
      }, 1000);
    }
  },

dispatch的上下文 就是这个store实例对象


12.还是看效果吧


点击异步修改的时候报错

Z46WHY(5D)W4K8WM$P811UF.png


13. this解决方案


这里借用 react的一种解决方案

就是在 构造函数里绑定 函数的作用域


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

自己可以尝试还有哪些解决方案


14.完美的效果,忍不住录个屏吧


4B3U_Y4Y56HT95XO$P@R~M3.png



15. 附上完整的 zvuex.js



let Vue
class Store {
    constructor(options) {
        console.log(" options:",options);
        console.log(" this:",this);
        // 保存数据
        // this.$options = options
        this._mutations = options.mutations
        this._actions = options.actions
        // Vue.util.defineReactive(this,'state',{})
        // 用户访问 name 并且轻松修改了 这不是我们想看到的
        // this._vm.name ="修改了"
        this._vm = new Vue({
            data() {
                return {
                    // 不做代理
                    $$state:options.state,
                    // name:"yzs"
                }
            }
        })  
        // react的做法
        // 绑定 this
        this.commit = this.commit.bind(this)
        this.dispatch = this.dispatch.bind(this)
    }
    get state(){
        // 这里的访问就比较深了 ,就是不想用户简单的就访问了我们的数据
        return this._vm._data.$$state
    }
    set state(z){
        console.error("请使用 replaceState 重置state");
    }
    // 用法 store.commit("add",2)
    commit(type,payload) { 
        //根据type 从用户配置的 mutaions中 获取函数
      const entry =  this._mutations[type]
      if(!entry){
        return console.error("unknow mutaion")
      }
      entry(this.state,payload)
    }
    dispatch(type,payload) { 
        const entry =  this._actions[type]
        if(!entry){
          return console.error("unknow actions")
        }
        // dispatch 的上下文是 state实例 
        entry(this,payload)
    }
}
function install(_Vue, options) {
    Vue = _Vue
    Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}
export default { Store, install }




相关文章
|
1天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
1天前
|
存储 JavaScript
Vue 组件间如何通信
Vue组件间通信是指在Vue应用中,不同组件之间传递数据和事件的方法。常用的方式有:props、自定义事件、$emit、$attrs、$refs、provide/inject、Vuex等。掌握这些方法可以实现父子组件、兄弟组件及跨级组件间的高效通信。
|
6天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发
|
6天前
|
存储 JavaScript
Vue 状态管理工具vuex
Vue 状态管理工具vuex
|
13天前
|
缓存 JavaScript UED
Vue 中实现组件的懒加载
【10月更文挑战第23天】组件的懒加载是 Vue 应用中提高性能的重要手段之一。通过合理运用动态导入、路由配置等方式,可以实现组件的按需加载,减少资源浪费,提高应用的响应速度和用户体验。在实际应用中,需要根据具体情况选择合适的懒加载方式,并结合性能优化的其他措施,以打造更高效、更优质的 Vue 应用。
|
12天前
|
JavaScript
如何在 Vue 中使用具名插槽
【10月更文挑战第25天】通过使用具名插槽,你可以更好地组织和定制组件的模板结构,使组件更具灵活性和可复用性。同时,具名插槽也有助于提高代码的可读性和可维护性。
15 2
|
12天前
|
JavaScript
Vue 中的插槽
【10月更文挑战第25天】插槽的使用可以大大提高组件的复用性和灵活性,使你能够根据具体需求在组件中插入不同的内容,同时保持组件的结构和样式的一致性。
14 2
|
12天前
|
前端开发 JavaScript 容器
在 vite+vue 中使用@originjs/vite-plugin-federation 模块联邦
【10月更文挑战第25天】模块联邦是一种强大的技术,它允许将不同的微前端模块组合在一起,形成一个统一的应用。在 vite+vue 项目中,使用@originjs/vite-plugin-federation 模块联邦可以实现高效的模块共享和组合。通过本文的介绍,相信你已经了解了如何在 vite+vue 项目中使用@originjs/vite-plugin-federation 模块联邦,包括安装、配置和使用等方面。在实际开发中,你可以根据自己的需求和项目的特点,灵活地使用模块联邦,提高项目的可维护性和扩展性。
|
13天前
|
缓存 JavaScript UED
Vue 中异步加载模块的方式
【10月更文挑战第23天】这些异步加载模块的方式各有特点和适用场景,可以根据项目的需求和架构选择合适的方法来实现模块的异步加载,以提高应用的性能和用户体验