0

0

深入了解vuex的实现原理

青灯夜游

青灯夜游

发布时间:2023-03-20 18:14:08

|

2818人浏览过

|

来源于掘金社区

转载

当面试被问vuex的实现原理,你要怎么回答?下面本篇文章就来带大家深入了解一下vuex的实现原理,希望对大家有所帮助!

深入了解vuex的实现原理

关于vuex就不再赘述,简单回顾一下:当应用碰到多个组件共享状态时,简单的单向数据流很容易被破坏:第一,多个视图依赖于同一状态;第二,来自不同视图的行为需要变更同一状态。若解决前者使用传参的方式,则不适用于多层嵌套的组件以及兄弟组件;若解决后者使用父子组件直接引用或事件变更和同步状态的多份拷贝,则不利于代码维护。

所以,最好的办法是:把组件的共享状态抽取出,以一个全局单例模式管理!这也正是vuex背后的基本思想。

image.png

立即学习前端免费学习笔记(深入)”;

【相关推荐:vuejs视频教程web前端开发

所以,vuex的大致框架如下:

class Store {
    constructor() {
        // state
        // getters  
        // mutations
        // actions
    }
    // commit
    // dipatch
}

接下来,就写写看。

一、创建vue项目

vue create vue2-vuex//创建vue2项目

yarn add vuex@next --save//安装vuex

yarn serve//启动项目

二、实现原理

1、State

(1)使用

ModelGate
ModelGate

一站式AI模型管理与调用工具

下载
//store.js
// 仓库
import Vue from 'vue'
import Vuex from 'vuex'
import extra from './extra.js'

Vue.use(Vuex) //引入vuex的方式,说明Store需要install方法
export default new Vuex.Store({
    // 仓库数据源
    state: {
        count: 1,
        dowhat: 'addCount'
    },
}
//app.vue
<template>
    <div class="testState">
        <p>{{mycount}}</p>
        <p>{{dowhat}}:{{count}}</p>
    </div>
</template>

<script>
export default {
    import {
        mapState
    } from 'vuex'
    // 推荐方式
    computed: mapState()({
        mycount: state => state.count
    }),
    // 推荐方式的简写方式
    computed: {
        // 解构的是getters
        ...mapState(['count', 'dowhat'])
    },
  }
</script>

(2)注意

由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性 中返回某个状态,这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用 state 的组件中需要频繁地导入,并且在测试组件时需要模拟状态

Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)

(3)实现

所以除了Store内部的五大属性以外,还需要考虑插件的一个install方法,所以大致框架如下:

class Store {
    constructor() {
        // state
        // getters  
        // mutations
        // actions
        //modules
    }
    // commit
    // dipatch
}
let Vuex = {
    Store,
    Install
}
export default Vuex

所以,接下来就可以具体实现了,

class Store {
    constructor(options) {
        // state
        this.state = options.state
    }
}
let install = function(_Vue) {
    _Vue.mixin({
        beforeCreate() { //在组件创建之前自动调用,每个组件都有这个钩子
            if (this.$options && this.$options.store) { //this.$options读取根组件
                this.$store = this.$options.store
            } else {
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

然而,上述的state的实现有一个缺点:当改变数据的时候,state的数据不能动态的渲染。所以如何把state里的数据成为响应式成为关键问题?实际上,类似vue里的data,也可以通过这种方式让其成为响应式。那么就得从install方法中传入Vue,所以改变后:

let Vue=null
class Store {
    constructor(options) {
        // state
        this.vm = new _Vue({
          data: {
            state: options.state//data中的数据才是响应式
          }
        })
    }
      get state() {
        return this.vm.state
    }
}
let install = function(_Vue) {//用于Vue.use(plugin)
    Vue=_Vue
    _Vue.mixin({
        onBeforeCreate() { //在组件创建之前自动调用,每个组件都有这个钩子
            if (this.$options && this.$options.store) { //this.$options读取根组件
                this.$store = this.$options.store
            } else {
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

2、getters

(1)使用

//store.js
export default new Vuex.Store({
    // 计算属性
    getters: {
        // 这里的函数不需要调用,可以直接使用,官方默认前面有get
        getCount(state) {//接受 state 作为其第一个参数
            return state.count * 100;
        }
    },
}

(2)注意

有时候我们需要从 store 中的 state 中派生出一些状态(比如增加,删除,过滤等等),Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,Getter 接受 state 作为其第一个参数,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果

(3)实现

 // getters
    let getters = options.getters || {}
    this.getters = {}
    Object.keys(getters).forEach(getterName => {
      Object.defineProperty(this.getters, getterName, {
        get: () => {
          return getters[getterName](this.state)
        }
      })
    })

3、mutations

(1)使用

//store.js
export default new Vuex.Store({
        // 相当于methods
    mutations: {
        // mutations内部的函数,天生具备一个形参
        add(state, n) {
            state.count += n;
        },
        decrease(state, n) {
            state.count -= n;
        }
    },
}
methods: {
            submit() {
                console.log('success');
            },

            // 解构仓库mutations里面的方法,要啥解构啥
            ...mapMutations(['add', 'decrease']),
            // this.$store.commit('add'),
                
            ...mapActions(['addAction', 'decreaseAction']),
            // this.addAction()调用actions里面的方法
            // this.$store.dispatch('add'),
}

(2)注意

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler) 。这个回调函数就是进行状态更改的地方,并且它会接受 state 作为第一个参数,不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法

可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload) ,在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读

(3)实现

   // mutations
    let mutations = options.mutations || {}
    this.mutations = {}
    Object.keys(mutations).forEach(mutationName => {
      this.mutations[mutationName] = (arg) => {//保证多个(第二个)参数的传入
        mutations[mutationName](this.state, arg)
      }
    })
    
    commit = (method, arg) => {//使用箭头函数改变被调用的this的指向
        // console.log(this);
        this.mutations[method](arg)
  }

4、actions

(1)使用

//store.js
export default new Vuex.Store({
    actions: {
        addAction(context) {
            // 在这里调用add方法
            context.commit('add', 10);
        },
        decreaseAction({
            commit
        }) {
            commit('decreaseAction', 5)
        }
    },
}

(2)注意

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作
  • Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象
  • Action 通过 store.dispatch 方法触发
  • Action 通常是异步的,store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise
  • 一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行

(3)实现

    // actions
    let actions = options.actions || {}
    this.actions = {}
    Object.keys(actions).forEach(actionName => {
      this.actions[actionName] = (arg) => {
        actions[actionName](this, arg)
      }
    })
    
   dispatch=(method, arg) =>{
    this.actions[method](arg)
  }

5、modules

(1)使用

    // actions
    let actions = options.actions || {}
    this.actions = {}
    Object.keys(actions).forEach(actionName => {
      this.actions[actionName] = (arg) => {
        actions[actionName](this, arg)
      }
    })
    
   dispatch=(method, arg) =>{
    this.actions[method](arg)
  }
    //store.js
    modules: {
        extra: extra
    }

(2)注意

  • 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿,Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
  • 对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象
  • 对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState
  • 对于模块内部的 getter,根节点状态(rootState)会作为第三个参数暴露出来

三、整体代码

let Vue = null//全局的_Vue

class Store {
  constructor (options) {
    // state
    //this.state = options.state 写法不完美,当改变数据的时候,不能动态的渲染,所以需要把data中的数据做成响应式的
    this.vm = new _Vue({
      data: {
        state: options.state//data中的数据才是响应式
      }
    })

    // getters
    let getters = options.getters || {}
    this.getters = {}
    Object.keys(getters).forEach(getterName => {
      Object.defineProperty(this.getters, getterName, {
        get: () => {
          return getters[getterName](this.state)
        }
      })
    })

    // mutations
    let mutations = options.mutations || {}
    this.mutations = {}
    Object.keys(mutations).forEach(mutationName => {
      this.mutations[mutationName] = (arg) => {//保证多个(第二个)参数的传入
        mutations[mutationName](this.state, arg)
      }
    })

    // actions
    let actions = options.actions || {}
    this.actions = {}
    Object.keys(actions).forEach(actionName => {
      this.actions[actionName] = (arg) => {
        actions[actionName](this, arg)
      }
    })

  }

  dispatch=(method, arg) =>{
    this.actions[method](arg)
  }

  commit = (method, arg) => {
    // console.log(this);
    this.mutations[method](arg)
  }

  get state() {
    return this.vm.state
  }

}

let install = function(_Vue) {
  Vue = _Vue
  Vue.mixin({
    beforeCreate() {//在组件创建之前自动调用,每个组件都有这个钩子
      if (this.$options && this.$options.store) {  // this.$options读取到根组件
        this.$store = this.$options.store
      } else { // //如果不是根组件的话,也把$store挂到上面,因为是树状组件
        this.$store = this.$parent && this.$parent.$store
      }
    }
  })
}

let Vuex = {
  Store,
  install
}

export default Vuex

(学习视频分享:vuejs入门教程编程基础视频

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

46

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

178

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

51

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

92

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

102

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

227

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

532

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

171

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号