为什么会有 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. GeoServer 查询sql视图

    说明: 最近项目中遇到一个需求,需要统计管网的长度,但管网数据量非常大,前端用openlayers接口统计直接就奔溃了. 后尝试使用调后台接口查数据库的方式,虽然可行但是又要多一层与后台交互的工作. ...

  2. PHP 模板引擎

    PHP模板引擎的由来 ● 为了解决当时混合开发WEB应用出现的一系列问题:代码难维护,代码不可重用,程序员要求知识广等问题 ● 实现后端与前端不完全分离,开发与美工可以分工合作,提高效率 PHP模板引 ...

  3. 程序员用于机器学习数据科学的3个顶级 Python 库

    NumPy NumPy(数值 Python 的简称)是其中一个顶级数据科学库,它拥有许多有用的资源,从而帮助数据科学家把 Python 变成一个强大的科学分析和建模工具.NumPy 是在 BSD 许可 ...

  4. JVM学习笔记(1)--运行时数据区域

    运行时数据区域 相对于c,c++.程序设计时,java并不需要手动释放或者创建内存用于存放程序,这的确使得java开发变得容易和轻松,一旦有一天出现了内存泄漏或者内存溢出的问题,如果不了解JVM虚拟机 ...

  5. Linux -- 进程管理之僵尸进程

    UNIX 存在一种机制:在每个进程退出的同时,操作系统释放该进程所有资源,但仍然保留一定的信息(PID / Status / runtime),直到父进程执行 wait() / waitpid(),以 ...

  6. Java语法进阶10-多线程

    多线程 并发与并行.进程,线程调度自行百度 线程(thread):是一个进程中的其中一条执行路径,CPU调度的最基本调度的单位.同一个进程中线程可以共享一些内存(堆.方法区),每一个线程又有自己的独立 ...

  7. Lua和C交互的简易教程

    转载请标明出处:http://blog.csdn.net/shensky711/article/details/52458051 本文出自: [HansChen的博客] Lua栈 要理解Lua和C++ ...

  8. 【搞定面试官】你还在用Executors来创建线程池?会有什么问题呢?

    前言 上文我们介绍了JDK中的线程池框架Executor.我们知道,只要需要创建线程的情况下,即使是在单线程模式下,我们也要尽量使用Executor.即: ExecutorService fixedT ...

  9. LESSON 4- Entropy and Asymptotic Equipartition Property

    1.        Entropy 2.        序列熵(无记忆,有记忆,马尔科夫) 3.   Fixed-to-variable-length codes  (给n个输出symbols进行变长 ...

  10. C++桌面计算机

    #include<iostream> #include<string> #include<map> #include<cctype> using nam ...