Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
{{ count }}
`,
// actions
methods: {
increment () {
this.count++
}
}
})
这里有一段代码,我们可以将它分为三个部分,即数据源、可视界面和行为;
这个状态自管理应用包含以下几个部分:
我们可以把它看作单向数据流,在actions中首先让变量count自增,然后在将自增后的值替换state中原来的值,最后将最新得到的值渲染到view界面中。
下面是“单向数据流”理念的简单示意图:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
为了更高效的解决上述问题,我们可以考虑把组件的共享状态抽取出来,以一个全局单例模式管理,在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为。这样通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
使用Vuex统一管理状态的好处:
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。
1、当一个组件需要多次派发事件时
2、跨组件共享数据、跨页面共享数据
npm install vuex --save
import Vuex from 'vuex'
Vue.use(Vuex) //将vuex安装到项目中
const store = new Vue.Store({
//state 中存放的就是全局的共享数据
state: { count: 0 }
})
new Vue ({
el: '#app',
render: h => h(app), //渲染app根组件
route, //挂载路由
//将创建的共享数据对象,挂载到Vue实例中
//所有的组件,就可以直接从store中获取全局的数据了
store
})
State提供唯一的公共数据源,所有的共享的数据都要统一放到Store的State中进行存储。
//首先new一个Vuex.Store的构造函数从而得到了一个store的实例对象
const store = new Vue.Store({
//state 中存放的就是全局的共享数据
state: { count: 0 }
})
组件访问State中数据的方式:
this.$store.state.全局数据名称
例子:
这是store.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
}
})
这是Add.vue文件
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}h3>
div>
template>
<script>
export default {
data() {
return {}
}
}
script>
组件访问State中数据的第二种方式:
//1. 从vuex中按需导入mapState函数
import { mapState } from 'vuex'
//2. 通过刚才导入的 mapState 函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
computed: {
...mapState(['count'])
}
例子:
这是Sub.vue文件
<template>
<div>
<h3>当前最新的count值为:{{count}}h3>
div>
template>
<script>
import { mapState } from 'vuex'
export default {
data() {
return {}
},
//定义一个计算属性,然后在计算属性中调用mapState函数
computed: {
//展开运算符,
...mapState(['count']),
}
}
script>
Mutations用于变更Store中的数据。他有下面两种特点:
例子:
//store.js
//在state平级下面创建mutations,他后面对应一个对象,里面可以定义很多事件处理函数
export default new Vuex.Store({
state: {
count: 0
},
// 只有 mutations 中定义的函数,才有权利修改 state 中的数据
mutations: {
addN(state, step) {
state.count += step
},
subN(state, step) {
state.count -= step
}
},
actions: {},
getters: {}
})
//Add.vue
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}h3>
<button @click="btnHandler1">+Nbutton>
div>
template>
<script>
export default {
data() {
return {}
},
methods: {
btnHandler1() {
//当我们点击按钮之后我们希望能调用全局中的AddN函数
// commit 的作用,就是调用 mutation中的某个函数
this.$store.commit('addN', 3)
}
}
}
script>
this.$store.commit() 是触发mutation的第一种方式,还有第二种方式:
//1.从vuex中按需导入mapMutations函数
import { mapMutations } from 'vuex'
//2.将指定的mutations函数映射为当前组件的methods函数
methods: {
...mapMutations(['addN'])
}
例子:
<template>
<div>
<h3>当前最新的count值为:{{count}}h3>
<button @click="btnHandler1">-Nbutton>
div>
template>
<script>
//从vuex中按需导入mapMutations函数
import { mapState, mapMutations} from 'vuex'
export default {
data() {
return {}
},
computed: {
...mapState(['count']),
},
methods: {
...mapMutations(['subN']),
btnHandler1() {
this.subN(3)
}
}
}
script>
当我们需要进行异步操作时,就要用到Action。Action 类似于 mutation,不同在于:
换句话说,如果想要通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要触发Mutation的方式来间接变更数据。
//store.js
export default new Vuex.Store({
state: {
count: 0
},
// 只有 mutations 中定义的函数,才有权利修改 state 中的数据
mutations: {
addN(state, step) {
// 不要在 mutations 函数中,执行异步操作
// setTimeout(() => {
// state.count++
// }, 1000)
state.count += step
}
},
actions: {
addNAsync(context, step) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的数据;
// 必须通过 context.commit() 触发某个 mutation 才行
context.commit('addN', step)
}, 1000)
}
},
getters: {}
})
//Add.vue
<template>
<div>
<h3>当前最新的count值为:{{$store.state.count}}h3>
<button @click="btnHandler">+N Asyncbutton>
div>
template>
<script>
export default {
data() {
return {}
},
methods: {
btnHandler() {
// 这里的 dispatch 函数,专门用来触发 action
this.$store.dispatch('addNAsync', 5)
}
}
}
script>
this.$store.dispatch()是触发action的第一种方式,下面是第二种方式:
//1.从vuex中按需导入mapActions函数
import { mapActions } from 'vuex'
//2.将指定的actions函数映射为当前组件的methods函数
methods: {
...mapActions(['addNAsync'])
}
<template>
<div>
<h3>当前最新的count值为:{{count}}h3>
<button @click="btnHandler">-Nbutton>
<button @click="addNAsync(3)">-Nbutton>
div>
template>
<script>
//从vuex中按需导入mapMutations函数
import { mapState, mapMutations, mapActions} from 'vuex'
export default {
data() {
return {}
},
computed: {
...mapState(['count']),
},
methods: {
...mapMutations(['addNAsync']),
btnHandler() {
this.addNAsync(3)
}
}
}
script>
Getter用于对Store中的数据进行加工处理形成新的数据。
从vuex中按需导入mapGetters函数
将指定的getters函数映射为当前组件的computed函数