为什么会有 Vuex 这个东西 ?

现代前端框架主要解决的是 事件 -> 状态 -> UI 将传统前端在两个过程的代码剥离出来,变得更加容易维护;

vue的声明式渲染,解决了 状态 和 UI 的同步问题,从而使我们不需要由于状态发生改变去写大量的命令式改变 dom 的代码。

而类似于 vuex 这类状态管理的库,则解决了 事件 -> 状态 这个过程的维护问题。这类库所做的事情就是管理从 事件源映射到状态变化 这个过程(将这个映射过程从视图组件中剥离出来,组织好这一部分的代码,在组件外部进行状态的管理)

具体表现就是一个全局的数据中心 store 配置,每个组件进行更新的时候就通知数据中心,数据中心改变后,再去触发每个调用它的组件进行更新(这种更新是响应式的);几个核心概念就是 mutations里的方法可以直接 mutatestore 中的状态,并且 mutation 过程必须同步的,需要通过 commit 去触发;而 actions 则允许异步的操作,通过 commit 去触发 mutation ,达到间接修改 store的目的,action 本身需要通过 disptch去触发。

Vuex与全局对象的区别

其实,vuex 与全局对象有一定的共同之处,那就是状态会被全局共享,无论是嵌套多少组件…

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是 响应式 的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到 高效更新
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

Vuex常见的应用场景

管理状态与共享状态

应用简单时,可以使用 propevent 来完成 父子组件 的通信。使用 global event bus(event bus)来实现 简单的非父子组件之间的跨组件 通信。但对于 多层级组件嵌套 等较为复杂的场景,使用 vuex 能更好地应对。(使用 event bus 的缺点是当状态较复杂,调用组件非常多,要挨个依次通知所有组件更新;每个组件对这个组件进行的状态更新都要通知监听该事件的所有组件;这样会变得非常复杂)(你通知我, 我通知你, 你通知他, 他通知我 ... 大家之间是直接相互作用的)

vuex 状态管理模型,拥有一个统一的数据中心Store,Store用来维护状态数据;每个组件进行更新的时候就通知数据中心,数据中心改变后,再去统一触发每一个调用它的组件进行更新(相当于由数据中心来统筹状态变化以及状态变化的分发,而不是由每个vue组件直接去操作state) (有点类似于中介者模式, 大家把所有各种类型的信息都反馈给中介, 然后再由中介分发给订阅了某个类型信息的用户)

图解

vuex 是通过将 state 作为数据中心,各个组件 共享 state 来实现跨组件通信的, 此时的数据完全独立于组件。(点击不同模块的操作,不再需要去发送乱七八糟的事件, 只是去调用事件中心里的 mutation 动作, 从而实现模块间共享状态的功能)

需要构建一个中大型单页应用时,很可能会考虑如何更好地 在组件外部 管理状态

vuex更多地用于解决 跨组件通信 (多层嵌套组件之间的通信问题)以及作为 数据中心集中式存储数据 (管理应用中错综复杂的状态关系)

vuex 作为数据存储中心

vuexstate在单页应用的开发中本身具有一个 数据库 的作用,可以将组件用到的数据存储在 state中,并在 actions中封装数据读写的逻辑。目前主要有两种数据会使用 vuex进行管理

  1. 组件之间 全局共享 的数据
  2. 通过后端异步请求的数据

实际项目开发中更多的是用到第二种,即把通过后端异步请求的数据都纳入 vuex 状态管理,在 actions 中封装数据的增删改查等逻辑,这样可以在一定程度上对前端的逻辑代码进行分层,使组件中的代码更多地关注页面交互与数据渲染等 视图层 的逻辑,而异步请求与状态数据的持久化等则交由 vuex 管理

一般全局数据,会使用到 vuex 来管理。比如 用户数据,系统数据 等,这些数据很多组件中都会使用,我们当然可以每次使用的时候都去请求,但是出于程序员的“洁癖”、“抠”等等优点,还是希望一次请求,到处使用。

这时候很自然的想到存储在 localStorage 中,但是有个问题是,这些数据可能会变,如果没能及时 同步 的话,就会用到不正确的数据,即使做了数据同步,但是 localStorage 中的数据不是响应式的,不能自动更新使用到这些数据的地方。这时候就想要开始使用 vuex了。

Vuex代码的组织方式

vue-router 类似,有非模块化写法与模块化写法(其实无论何种写法本质上是一样的,目的就是导出一份 router或者 store 的配置数据)

以管理 count 与 用户信息 userinfo 为例,介绍 vuex代码的组织方式

核心概念 state,getter,mutation,action,module

vuex 需要遵守的规则

应用层级的状态应该集中到 单个 store 对象中

mutation是直接操作state的方法(唯一能改变状态的方法),过程要求必须同步

action 通过commit去触发mutation,从而间接修改状态,优点是允许异步逻辑,

非模块化写法
// 1.安装 vuex

// 2.在入口文件中引入
// main.js
import Vuex from 'vuex' // 3.Vue使用 vuex 插件
Vue.use(Vuex) // 4.生成数据管理中心 store
const store = new Vuex.Store({
    state: {
        userinfo: null, // 需要给定初始值
        count: 0
    },
    // 直接通过mutation方法来mutate操作state; 只能以同步的方式; mutation方法需要通过commit来触发
    mutations: {
        userinfo: function (state, payload) {
              state.userinfo = options
            localStorage.userinfo = JSON.stringify(state.userinfo)
        },
        increment: function (state, payload) {
            state.count += payload.amount
        }
    },
    // 通过commit触发mutations里的mutation方法, 以此间接修改 state; 允许异步操作;action方法需要通过dispatch来触发
    actions: {
        increment: function (context, payload) {
            context.commit('increment', payload)
        },
        incrementAsync: function (context) {
            // 异步请求数据
            setTimeout(() => {
                var amount = 10; // 模拟异步请求得到数据
                context.commit('increment', { amount })
            }, 1000)
        },
        async userinfo (context) {
            let response = await getUserInfo() // 异步请求后端数据 方法需要 import
            if (response.ok) {
                let json = await response.json()
                context.commit('userinfo', json)
            }
        }
    },
    getters: {// 处理、过滤数据     }
}) // 5.通过 store 配置参数注入状态管理,从而任何组件可通过 this.$store 访问状态中心
new Vue({
    el: '#app',
    store, // (*)
    render: function (h) {
        return h(App)
    }
})
模块化写法
// 1.安装vuex

// 2.引入
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// import ... // 3.Vue使用 vuex 插件
Vue.use(Vuex) // 4.分模块生成数据管理中心
// 配置 userinfo 状态模块 (还能再单独拆出一个文件,然后import进来)
const moduleA = {
    state: {
        userinfo: null // 需要初始化响应式数据
    },
    mutations: {
        userinfo: function (state, options) {
            state.userinfo = options
            localstorage.userinfo = JSON.stringify(state.userinfo)
        }
    },
    actions: {
        async userinfo (context) {
            async userinfo (context) {
                let response = await response.json()
                if (response.ok) {
                    let json = await response.json()
                    context.commit('userinfo', json)
                }
            }
        },
        getters: {// 处理、过滤数据         }
    }
} // 配置 count 状态模块 (还能再单独拆出一个文件,然后import进来)
const moduleB = {
    state: {
        count: 1,
    },
    mutations: {
        increment:function (state, payload) {
            state.count += payload
        },
    },
    actions: {
        increment: function (context, payload) {
              context.comit('increment', payload)  
        },
          incrementAsync: function (context) {
            // 异步请求数据
            setTimeout(() => {
                var amount = 10; // 模拟异步请求得到数据
                context.commit('increment', { amount })
            }, 1000)
        },  
    },
    getters: {
        doubleCount (state) {
            return state.count * 2
        }
    }
} // 5.导出一份 store 的配置
export default new Vuex.Store({
    modules: { // 这里与非模块化写法有点不一样;原来整个对象是一份配置...
        a: moduleA,
        b: moduleB,
    }
}) // store.state.a // -> moduleA 的状态
// store.state.b // -> moduleB 的状态 // 6.在根脚本 main.js 中引入 store 配置
import store from './store'
...
// 并通过 store 配置参数注入状态管理,从而任何组件可通过 this.$store 访问状态中心
new Vue({
    el: '#app',
    router,
    store,
    render: function (h) {
        return h(App);
    }
});

在不同组件中使用或操作状态

// 根组件
// App.vue
// 在生命周期中触发全局共享数据的获取
...
mounted () {
    if (!this.$store.state.userinfo) { // this.$store.state.a.userinfo 模块化写法的话
        this.$store.dispatch('userinfo')
    }
} // 使用 state 的数据
computed: {
    userinfo () {
        return this.$store.state.userinfo
        // return this.$store.state.a.userinfo // 模块化写法的话
    },
    count () {
        return this.$store.state.count
        // return this.$store.state.b.count // 模块化写法的话
    }
}
// 子组件
// NavBar.vue
...
// 改变 state 的数据
methods: {
    // 使用 commit 触发 mutations 中的 mutation 方法,直接修改 state 中的数据
    addOne () {
        this.$store.commit('increment', { amount: this.price })
    },
    // 使用 dispatch 触发 actions 中的 action 方法;异步修改 state 中的数据
    addTenAsync () {
        this.$store.dispatch('incrementAsync')
    }
} // 使用 state 的数据
computed: {
    userinfo () {
        return this.$store.state.userinfo
        // return this.$store.state.a.userinfo // 模块化写法的话
    }
}
// 路由页面组件
// Manage.vue
...
// 改变 state 的数据
methods: {
    addTwo () {
        this.$store.commit('increment', { amount: this.price })
    }
} // 使用 state 的数据
computed: {
    count () {
        return this.$store.state.count
        // return this.$store.state.b.count // 模块化写法的话
    }
},

总之,使用了 vuex 来管理状态,点击不同模块的操作,不再需要去发送乱七八糟的事件, 只是去调用事件中心里的 mutation 动作, 从而实现模块间共享状态的功能;修改一处,全局共享(无论是组件还是路由页面组件都能同步)

最后,再看看 vuex 官网的这张说明图,是不是更加清晰了呢!

虚线绿框里即vuex做的事

-项目地址- vuex-demo

[vue]初探vue生态核心插件Vuex的更多相关文章

  1. vue从入门到精通之【vuex】(七)

    vue从入门到精通之[vuex](七) vuex一个公用的大仓库,Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架. Vuex 实现了一个单向数据流,在全局拥有一个 state 存放数据, ...

  2. vue.js 开发生态总结

    ---title: Vue 1.0 的技术栈date: 2016-09-26 00:48:50tags:category:--- ## vuejs概述 Vue.js是用于构建交互式的Web界面的库.它 ...

  3. 【vue】vue +element 搭建项目,vuex中的store使用

    概述: 每一个 Vuex 应用的核心就是 store(仓库).“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state).Vuex 和单纯的全局对象有以下两点不同: Vuex 的 ...

  4. day 87 Vue学习六之axios、vuex、脚手架中组件传值

      本节目录 一 axios的使用 二 vuex的使用 三 组件传值 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 axios的使用 Axios 是一个基于 promise 的 HT ...

  5. [译]怎样在Vue.js中使用jquery插件

    原文:http://gambardella.info/2016/09/05/guide-how-to-use-vue-js-with-jquery-plugins 使用Vue真的太棒了,但是也有可能使 ...

  6. Vue 爬坑之路—— 使用 Vuex + axios 发送请求

    Vue 原本有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource 目前主流的 Vue 项目,都选择 axios  ...

  7. day 84 Vue学习六之axios、vuex、脚手架中组件传值

    Vue学习六之axios.vuex.脚手架中组件传值   本节目录 一 axios的使用 二 vuex的使用 三 组件传值 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 axios的 ...

  8. 【Vue】Vue学习(四)-状态管理中心Vuex的简单使用

    一.vuex的简介 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.Vuex背后的基本思想,就是前面所说的单向数据流.图4就是Vuex实现单向数据流的示意图.    Store     ...

  9. vue初探

    vue初探 很多同学一定都听过MVVM.组件.数据绑定之类的专业术语,而vue框架正是这样的一种框架.vue的作用是:通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 第一部分:vue介 ...

随机推荐

  1. nyoj 833-取石子(七) (摆成一圈,取相邻)

    833-取石子(七) 内存限制:64MB 时间限制:1000ms 特判: No 通过数:16 提交数:32 难度:1 题目描述: Yougth和Hrdv玩一个游戏,拿出n个石子摆成一圈,Yougth和 ...

  2. CSS中越界问题的经典解决方案

    (1)如何解决父元素的第一个子元素的margin-top越界问题 1)为父元素加border-top: 1px;——有副作用 2)为父元素指定padding-top: 1px;——有副作用 3)为父元 ...

  3. [ch02-00] 反向传播与梯度下降的通俗解释

    系列博客,原文在笔者所维护的github上:https://aka.ms/beginnerAI, 点击star加星不要吝啬,星越多笔者越努力. 第2章 神经网络中的三个基本概念 2.0 通俗地理解三大 ...

  4. 【SpringBoot | Redis】SpringBoot整合Redis

    SpringBoot整合Redis 1. pom.xml中引入Redis相关包 请注意,这里我们排除了lettuce驱动,采用了jedis驱动 <!-- redis的依赖 --> < ...

  5. systemd概念和运行机制

    systemd概念 核心概念:单元 依赖关系 systemd事务 启动目标和运行级别 单元 早期CentOS版本中的服务管理脚本在CentOS7中被服务但源文件替换.系统初始化需要启动后台服务,需要完 ...

  6. linux后台运行程序--nobup

    用途:不挂断地运行命令. 语法:nohup Command [ Arg - ] [ & ] 描述:nohup 命令运行由 Command 参数和任何相关的 Arg 参数指定的命令,忽略所有挂断 ...

  7. 【Luogu P2024&P1892】食物链&团伙(并查集拓展域)

    Luogu P1892 Luogu P2024 这两道一眼看过去很容易发现可以用并查集来做--但是当我们仔细阅读题面后,会发现其实并没有那么简单. 我们知道并查集可以很轻松地维护具有传递性的信息,也就 ...

  8. Mysql操作之查询语句

    查询语句: select 查询列表 from 表名 where 筛选条件; 去重:select distinct 查询列表...... 选择全部:* 起别名:select 查询列表 as 别名 fro ...

  9. RobotFramework自动化测试框架-Selenium Web自动化(三)关于在RobotFramework中如何使用Selenium很全的总结(下)

    本文紧接着RobotFramework自动化测试框架-Selenium Web自动化(二)关于在RobotFramework中如何使用Selenium很全的总结(上)继续分享RobotFramewor ...

  10. IEnumerable和IEnumerator详解

    引言 IEnumerable是可枚举的所有非泛型集合的基接口, IEnumerable包含一个方法GetEnumerator(),该方法返回一个IEnumerator:IEnumerator提供通过C ...