Niffler

X2.12 16340246-Vuex 使用详解

Posted By 16340246

Vuex

Vuex 是什么?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

—— Vuex 官方文档

在构建 Vue 单页面应用时,Vuex 为我们提供了全局状态管理。在 state 中定义的数据后,你可以在项目中任一个组件中进行获取或修改,并且你的修改可以得到全局的相应变更。当我们想要在项目中定义和使用全局变量时,使用 Vuex 是一个很好的解决方法。

  • state:对数据的全局存储
  • getter:和 Vue计算属性 computed 一样,来实时监听 state 值的变化 (最新状态)
  • mutations:对数据的同步更改
  • actions:对数据的异步更改

安装和引入

在你的 Vue 项目中安装 Vuex

npm install vuex --save

src 文件夹下创建一个 vuex 文件夹,并在 src/vuex 文件夹里新建一个 store.js,内容如下:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const store = new Vuex.Store()

export default store

main.js 中,通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。

import store from './vuex/store'

new Vue({
  el: '#app',
  router,
  store,	// 使用store
  render: h => h(App)
})

开始

在本示例中,我们要在 Vuex 中定义一个全局变量 isCollapse。在任一组件中,点击 展开/收起 按钮,将会将 isCollapse 变量取反,在项目中各个组件都根据这个变量来判断侧栏 (Side bar) 是否收起。为了说明参数传递的方法,下面还添加了 namenum 两个全局变量。

state

设置一个全局访问的 state 对象,并把它放到 store 里面


import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// 储存全局变量
const state = {
  // 要使用的全局变量初始值
  isCollapse: false,
  name: 'no one',
  num: 1
}

const store = new Vuex.Store({
  state
})

export default store

现在,在任一个组件中,通过 this.$store.state.isCollapsethis.$store.state.name 等,已经可以获取到这些全局变量了,但这并不是理想的方式,Vuex 提供了 getters,Vuex 允许我们在 store 中定义 “getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

getters

定义 getters,并把它放到 store 里面

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// 储存全局变量
const state = {
  // 要使用的全局变量初始值
  isCollapse: false,
  name: 'no one',
  num: 1
}

// 获取state中实时更新的值
const getters = {
  getIsCollapse (state) {
    return state.isCollapse
  },
  getName (state) {
    return state.name
  },
  getNum (state) {
    return state.num
  }
}

const store = new Vuex.Store({
  state,
  getters
})

export default store

现在,在任一组件中,使用如 this.$store.getters.getIsCollapse 就可以获取到这些变量。但是,我们通常还需要对全局变量进行更改,这就要用到 mutations 对象。

mutations

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。如下定义好 mutations,并把它放进 store 里面。

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// 储存全局变量
const state = {
  // 要使用的全局变量初始值
  isCollapse: false,
  name: 'no one',
  num: 1
}

// 获取state中实时更新的值
const getters = {
  getIsCollapse (state) {
    return state.isCollapse
  },
  getName (state) {
    return state.name
  },
  getNum (state) {
    return state.num
  }
}

// mutations: 对数据的同步更改
const mutations = {
  mutationsIsCollapse (state) {
    state.isCollapse = !state.isCollapse
  },
  mutationsName (state, payload) {
    state.name = payload.value
  },
  mutationsNum (state, payload) {
    state.num += payload.value
  }
}

const store = new Vuex.Store({
  state,
  getters,
  mutations
})

export default store

现在你可以使用 this.$store.commit 方法来修改 store 的数据:

this.$store.commit('mutationsIsCollapse')

注意到你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)。比如你要修改 num,你可以直接传递一个数字,但我们通常不会这么做,大多数情况下,payload 应该是一个对象:

this.$store.commit('mutationsIsCollapse', {
  key: 'num',
  value: 5
})

注意:对于 mutations 以及接下来的 action,你向他们传递的额外参数只能有一个,如果传递两个或多个额外参数,那么除了第一个参数,其他都将变成 undefined。因此,如果你要传递对个参数,请把他们放进 payload 里。

现在我们可以通过 mutations 来修改数据了,但要记住 mutations 里面的函数都是同步函数。按照官方文档对这里的解释是:

现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools 都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。

因此这不是理想的改变数据的方法,我们要使用 actions 对数据进行异步修改

actions

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

让我们定义 actions 对象并把它放进 store 里:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// 储存全局变量
const state = {
  // 要使用的全局变量初始值
  isCollapse: false,
  name: 'no one',
  num: 1
}

// 获取state中实时更新的值
const getters = {
  getIsCollapse (state) {
    return state.isCollapse
  },
  getName (state) {
    return state.name
  },
  getNum (state) {
    return state.num
  }
}

// mutations: 对数据的同步更改
const mutations = {
  mutationsIsCollapse (state) {
    state.isCollapse = !state.isCollapse
  },
  mutationsName (state, payload) {
    state.name = payload.value
  },
  mutationsNum (state, payload) {
    state.num += payload.value
  }
}

// actions: 对数据的异步更改
const actions = {
  changeIsCollapse (context) {
    context.commit('mutationsIsCollapse')
  },
  setName (context, payload) {
    context.commit('mutationsName', payload)
  },
  setNum (context, payload) {
    context.commit('mutationsNum', payload)
  }
}

const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

export default store

actions 通过this.$store.dispatch 方法触发:

this.$store.dispatch('changeIsCollapse')
this.$store.dispatch('setName', {
  key: 'name',
  value: 'someone'
})
this.$store.dispatch('setNum', {
  key: 'num',
  value: 5
})

这样就可以对全局数据进行更改了。记住,我们不要使用 mutations 对数据进行更改,而是要使用 actions。这样一来,修改全局数据后,在项目的任意组件中都可以使用 getters 来获取全局数据最新的值。