前言
Vuex 是做什么的?官方的解释是一个专为 vue.js 应用程序开发的状态管理模式,采用集中式存储管理应用所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。看完是不是一脸问号,状态管理到底是什么?其实可以将其看成把需要多个组件共享的变量全部存储在一个对象里,将这个对象放在最顶层的 vue 实例中,让其他组件可以使用
安装
在脚手架里,我们可以通过创建项目时勾选 vuex 的选项,系统会自动创建
也可以通过 npm 下载npm install vuex --save
配置
新建一个 store 文件夹->新建 index.js 进行配置,如果是通过脚手架创建 vuex 无需配置
import Vue from 'vue'
import Vuex from 'vuex'
//安装插件
Vue.use(Vuex)
//创建对象
const store=new Vuex.Store({
state:{
},
mutations:{
},
actions:{
},
getters:{
},
modules:{
}
})
//导出store对象
export defaule store
复制代码
main.js 中引入
import store from 'store路径'
new Vue({
el:'#app',
store,//Vue.prototype.$store=store
render: h => h(App)
})
复制代码
核心概念
在 Vuex 里有几个比较核心的概念:
State
Mutations
Getters
Actoins
Modules
state
state 用来保存状态,类似 data,例如在 state 里保存一个 count 状态,在任意组件里都可以拿来使用
state:{
count:10000
}
//任意组件里使用,直接展示
<div>{{$store.state.count}}</div>
复制代码
如何修改 state
<div>{{$store.state.count}}</div>
<button @click="$store.state.count++">+</button>
<button @click="$store.state.count--">-</button>
复制代码
那么状态需要修改时怎么做呢?很多人会像上面一样修改,但是这样后续调试的时候会出问题的,对于怎么修改,官方给出了一张图,如下:
从这张图的 state 开始顺着箭头走,state 提供数据给 vue 组件,vue 组件想要修改 state 得发布一个行为 actions,发布之后提交到 mutations 里,在 mutations 里修改 state。听起来是不是更复杂?
为什么官方希望我们这么做,图里有一个 Devtools,这是 vue 开发的一个浏览器插件,可以帮助我们记录修改后的 state 状态,可以进行跟踪,但是直接在 vue 组件里修改 state,devtools 是记录不到的
既然 devtools 是在 mutations 进行记录追踪,那 actions 是干嘛的?其实我们可以跳过 actions,直接在 vue 组件里通过 mutations 修改 state
当我们修改的时候有异步操作的时候,才需要通过 actions 操作完后提交到 mutations 再进行同步操作,因为 devtools 是跟踪不到异步操作的
下载 devtools浏览器插件地址
mutations 的基本使用
当我们直接去修改 state 里的状态时,devtools 并不会记录下来
那我们如何通过 mutations 修改?
mutations:{
inc(state){//默认传入一个state,对应上面的state对象
state.count++
},
dec(state){
state.count--
}
}
//方法1
<div>
<div>{{$store.state.count}}</div>
<button @click="$store.commit('inc')">+</button>//通过commit方法传入mutations里定义的方法的名字
<button @click="$store.commit('dec')">-</button>
</div>
//方法2
methods: {
inc(){
this.$store.commit('inc')//通过commit方法传入mutations里定义的方法的名字
},
dec(){
this.$store.commit('dec')
}
},
<div>
<div>{{$store.state.count}}</div>
<button @click="inc">+</button>
<button @click="dec">-</button>
</div>
复制代码
通过 mutations 修改 state,devtools 会追踪到并且记录下来,我们开发时就可以通过历史记录来追踪发现哪一步发生了错误
mutations 传递参数
例如:当上面案例再添加 n 个按钮去加或减不同的值,我们再去创建 n 个方法来修改,显然这是不对的,我们只要定义一个方法,传入对应的参数就可以去实现这样的效果,那我们怎么在 mutations 里传递参数呢?
mutations:{
add(state,count){//接收参数
state.count+=count
},
subtract(state,count){
state.count-=count
}
},
methods: {
add(count){
this.$store.commit('add',count)//传递参数
},
subtract(count){
this.$store.commit('subtract',count)
}
},
<div>
<div>{{$store.state.count}}</div>
<button @click="add(5)">+5</button>
<button @click="subtract(5)">-5</button>
</div>
复制代码
getters 的使用
getters 类组件里的计算属性,什么是计算属性?当数据经过一系列变化之后再展示就是计算属性了,getters 也是一样,那如何使用呢?
getters:{
power(state){//默认传入一个state,对应上面的state对象
return state.count*state.count
}
}
<div>平方:{{$store.getters.power}}</div>
复制代码
actions 的使用
上面已经说过 mutations 中的方法必须是同步方法,我们在 mutatoins 里用 setTimeout 模拟一下异步操作看看会发生什么
//store.js
state:{
name:'aaa'
},
mutations:{
updateName(state){
setTimeout(() => {
state.name='bbb'
}, 1000);
}
},
//组件
<div>{{$store.state.name}}</div>
<button @click="updateName">修改名字</button>
methods: {
updateName(){
this.$store.commit('updateName')
}
},
复制代码
我们可以发现点击修改名字按钮后页面显示的名字发生了变化,但是 devtools 没有追踪记录到,还是'aaa',所以 mutations 中的方法必须是同步方法
那当我们有异步操作的时候怎么办?就得通过 actions 来先进行异步操作后提交到 mutations 再进行同步操作:
//store.js
state:{
name:'aaa'
},
mutations:{
updateName(state){
state.name='bbb'
}
},
actions:{
updateInfo(context){//上下文,当前可以理解为store对象
setTimeout(() => {
context.commit('updateName')//不能直接修改,修改state的唯一途径就是mutations
}, 1000);
}
},
//组件
<div>{{$store.state.name}}</div>
<button @click="updateName">修改名字</button>
methods: {
updateName(){
this.$store.dispatch('updateInfo')//调用actions里的方法是dispatch
}
},
复制代码
修改完之后点击按钮等待一秒,devtools 可以追踪记录到了
modules 的使用
当应用变得非常复杂时,store 对象就会变得非常臃肿,为了解决这个问题,Vuex 允许我们将 store 分割成模块(Modules),每个模块拥有自己的 state,getters,mutations,actions 等,下面是分割模块的例子:
const moduleA={
state:{
test:'模块a的state'
},
mutations:{},
getters:{},
actions:{}
}
const moduleB={
state:{},
mutations:{},
getters:{},
actions:{}
}
const store=new Vuex.Store({
modules:{
a:moduleA,
b:moduleB
}
})
复制代码
模块分好之后怎么调用里面的 state,getters 之类呢?除 state 之外其他 getters,mutations 调用和之前一样,但是 actions 里只能 commit 自己模块里的 mutaions,state 调用要加上模块的名字,例如调用上面的 state 就是<div>{{$store.state.a.test}}</div>
,为什么会这样呢,我们可以打开 devtools 工具看一下就知道了
模块 a 会被放在 state 里面,所以调用的时候要加上模块的名字
评论