vuex的使用
vuex是一种集中式管理状态的工具,他也是组件间通信的一种方式,他可以更加方便的在组件间共享数据。
vuex的原理图
vuex原理
在图中我们可以看到,红色方框指的是store,他里面存放了vuex最重要的三个东西,分别是:Actions,Mutations,State。他们都是对象,里面进行相关配置。
State存放着我们要共享的数据,也就是说我们将要共享的数据放进去,在组件中就不用写了。 我们在组件中使用dispatch方法向actions传递要进行的操作与数据,Actions一般会进行一些业务操作,之后使用commit传递给Mutations,Mutations对state中的数据今年操作,时候重新渲染页面。这就是一个大概的流程,具体流程我们在例子中体现。
打一个比方,组件是来饭店吃饭的客人,他点菜提交给服务员(Actions),之后服务员(Actions)将客人点的菜交给后厨(Mutations),后厨做菜(对数据进行操作)。
vuex的基本流程
一、配置vuex
1、下载vuex 在这里我使用的是vuex3版本
npm i vuex@3
2、配置store 在图中我们可以看到store存放着vuex的相关配置,所以我们要配置store 在src目录中新建一个文件夹:store,在里面建立index.js,书写相关配置
//引入vue
import Vue from 'vue'
//引入vuex
import Vuex from 'vuex'
//使用vuex
Vue.use(Vuex)
//创建actions
const actions={
}
//创建mutations
const mutations={
}
//创建state
const state={
}
//创建store并暴露,将相关配置放入其中
export default new Vuex.Store(
{
actions,
mutations,
state
}
)
在创建好store后,我们将他配置在main.js中,这是为了能让所有组件都能使用store.
import Vue from 'vue'
import App from './App.vue'
//引入store
import store from './store/index'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store,//配置store
beforeCreate(){
Vue.prototype.$bus=this//安装全局总线
}
}).$mount('#app')
这样子我们就可以使用vuex了。
二、一个例子
具体的流程我们在例子中体现。 我们有一个组件CountDemo,他可以实现,+ ,-, 和为奇数时再加, 等一秒再加四个功能。
为了简单说明vue的基本使用我们就先创建这一个组件(当然还有App组件)。 我们先不用vuex实现这四个功能。
<template>
<div>
<h2>当前求和为:{{sum}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<button @click='increment'>+</button>
<button @click='decrement'>-</button>
<button @click='oddIncrement'>奇数加</button>
<button @click='waitIncrement'>等一秒加</button>
</div>
</template>
<script>
export default {
name:'countDemo',
data(){
return{
sum:0,//求和
n:1//选择框的数据
}
},
methods:{
increment(){
this.sum+=this.n
},
decrement(){
this.sum-=this.n
},
oddIncrement(){
if(this.sum%2!==0){
this.sum+=this.n
}
},
waitIncrement(){
setTimeout(()=>{
this.sum+=this.n
},1000)
}
}
}
</script>
<style>
button{
margin: 5px;
}
</style>
还是很简单的,现在我们将sum交给vuex管理,所以在组件中就不写sum了
data(){
return{
n:1//选择框的数据
}
},
将他交给store中的states
const state={
sum:0
}
接下来,就是客人(组件)要点菜了,使用dispatch这个方法。我们先完成加法这个功能。
由于将sum交给了store中的state,所以在组件中我们就不能使用原来的方式来进行加法了,就先把原来increment等方法的内容删掉吧.
在CountDemo组件中,increment方法如下,在dispatch方法中我们要传入两个参数,第一个参数是,进行的操作名,有点类似于消息订阅与发布的那个消息名,第二个参数为我们传入的数据。
increment(){
this.$store.dispatch('jia',this.n)
},
这样客人(组件)就点好了菜,接下来就是服务员(actions)接收点的菜,并将菜传递给厨师(mutations).
在store中,action接收组件传递过来的操作与数据
const actions={
jia(context,value){
context.commit('JIA',value)
}
}
我们看到actions中存放的就是一些方法,方法名就是我们在组件中传递过来的操作名。方法有两个参数:context与value。value就是我们传递过来的数据。那么context是什么呢?
我们将context输出发现,他其实就是一个对象,里面有我们需要的一些东西,就比如说commit。使用
context.commit('JIA',value)
就可以将点的菜传递给厨师(mutations)。让厨师进行操作。
接下来就是厨师(mutations)做菜的环节了.
const mutations={
JIA(state,value){
state.sum+=value
}
}
我们发现有一个熟悉的身影但是又不太熟悉的东西,那就是‘JIA’,其实这就是那个我们传递过来的操作,在actions中用来大写其实就是为了区分一下,显得他比较重要,没啥特殊的意思。所以在mutations中也用大写。
mutation中也是一些方法,方法也有两个参数,state与vaule,这两个我们就比较熟悉了,state就是就是我们存放共享数据的地方,mutations是操作数据的地方所以拿到他,合乎情理。value就是我们传递过来的数据。 这样一整套vuex的流程就走完了,我们的加法功能也可以实现了。
接下来我们实现减法的功能:减法与加法基本是一致的。唯一的不同就是mutations操作数据是减法。我们重新捋一遍。
首先客人(组件)点菜
decrement(){
this.$store.dispatch('jian',this.n)
},
之后服务员(actions)将点的菜传递给厨师(mutations)
const actions={
jia(context,value){
context.commit('JIA',value)
},
jian(context,value){
context.commit('JIAN',value)
}
}
厨师(mutations)开始做菜
const mutations={
JIA(state,value){
state.sum+=value
},
JIAN(state,value){
state.sum-=value
}
}
这样减法功能也实现了。
三、带有业务逻辑的操作
现在我们实现第三个功能,当和为奇数时才能加。我们肯定明白首先要判断当前的和是否为奇数,才能决定是否进行进行加法计算。但是在哪里进行判断呢?其实从理论上来讲在组件中,在actions,在mutations中都可以取到sum的值,都可以进行判断,但是呢,我之前说过,一般在actions中会进行一些业务逻辑,比如判断,循环,发送ajax请求,所以我们在actions中进行判断。
老规矩先点菜
oddIncrement(){
this.$store.dispatch('oddIncrement',this.n)
},
之后在actions中判断,并且传递给mutations。
oddIncrement(context,value){
console.log(context);
if(context.state.sum%2!==0){
context.commit('JIA',value)
}
}
我们看到,在这里我并没有在写一个mutations操作,直接判断通过后,进行'JIA'的操作就好了。这样当和为奇数时再加,就完成了。
接下来类似我们在完成等一秒再加的操作,与和为奇数时再加。
点菜
waitIncrement(){
this.$store.dispatch('waitIncrement',this.n)
}
传菜
waitIncrement(context,value){
setTimeout(()=>{
context.commit('JIA',value)
},1000)
}
这样等一秒的操作就完成了。这就是vuex的基本操作流程。
优化一
在上个例子中我们发现,加法与减法的actions其实并没有业务逻辑,这种情况下,其实我们可以在组件中使用commit直接向mutations传递操作与参数,并不用在actions写东西了。
组件中
increment(){
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
},
在acctions中就不写我们当时写的 jia jian了。
优化二
现在我们增加一下需求,要在组件中新显示网站名字,与语言两项。并且这两个属性要交给 vuex保管。在store中的index.js中添加两个属性
const state={
sum:0,
webName:'稀土掘金',
language:'vuex'
}
在组件中显示
<h2>网站名字:{{$store.state.webName}}---语言:{{$store.state.language}}</h2>
效果
在组件中我们发现需要频繁的使用$store.state去读取state中的数据。这样不太符合vue的风格,所以为了解决这个问题。我们引入一个api---mapState。他可以帮助我们更方便的读取state中的数据。我们需要在computed中应用这个api。当然了需要引入在使用。
computed:{
...mapState({sum:'sum',webName:'webName',language:'language'})
}
这样我们就很方便的读取出来了state中的数据,在组件中就可以很方便的使用。
<h2>当前求和为:{{sum}}</h2>
<h2>网站名字:{{webName}}---语言:{{$store.state.language}}</h2>
mapState还有第二种写法
...mapState(['sum','webName','language'])
优化三
在之前组件的methods中,我们要点菜们也就是向actions中传递方法与参数(使用dispatch),要自己写如下代码
oddIncrement(){
this.$store.dispatch('oddIncrement',this.n)
},
waitIncrement(){
this.$store.dispatch('waitIncrement',this.n)
}
如果操作比较多的话,自己写就太烦了,为了解决这个问题,我们使用mapActions。可以帮助生产上面的代码。同样在使用前我们要引入。在methods中。
...mapActions({oddIncrement:'oddIncrement',waitIncrement:'waitIncrement'})
这样就会帮我们实现上面我们自己写的代码。还有一个问题,我们是需要传递参数的,参数怎么传递呢?在mapActions中我们并没有传递参数。这时就需要在结构中定义方法时传递参数。
<button @click='oddIncrement(n)'>奇数加</button>
<button @click='waitIncrement(n)'>等一秒加</button>
优化四
我们来回顾一下,我们们优化后的代码是什么样子
<template>
<div>
<h2>当前求和为:{{sum}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<button @click='increment'>+</button>
<button @click='decrement'>-</button>
<button @click='oddIncrement(n)'>奇数加</button>
<button @click='waitIncrement(n)'>等一秒加</button>
<h2>网站名字:{{webName}}---语言:{{language}}</h2>
</div>
</template>
<script>
import {mapState,mapActions} from 'vuex'
export default {
name:'countDemo',
data(){
return{
n:1
}
},
methods:{
increment(){
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
},
...mapActions({oddIncrement:'oddIncrement',waitIncrement:'waitIncrement'})
},
computed:{
...mapState(['sum','webName','language'])
}
}
</script>
<style>
button{
margin: 5px;
}
</style>
目前为止我们优化了读取state,优化了向actions中传递方法。
现在我们优化这几行代码
increment(){
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
},
这几句代码是直接向mutations中通信。如何优化呢?我们使用mapMutations,在使用前也需要引入
...mapMutations({increment:'JIA',decrement:'JIAN'}),
他同样帮助我们生成上面的代码。记得在结构中传参,这一点和mapStatas相同。 来看看我们最终优化的代码吧
<template>
<div>
<h2>当前求和为:{{sum}}</h2>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<button @click='increment(n)'>+</button>
<button @click='decrement(n)'>-</button>
<button @click='oddIncrement(n)'>奇数加</button>
<button @click='waitIncrement(n)'>等一秒加</button>
<h2>网站名字:{{webName}}---语言:{{language}}</h2>
</div>
</template>
<script>
import {mapState,mapActions,mapMutations} from 'vuex'
export default {
name:'countDemo',
data(){
return{
n:1
}
},
methods:{
...mapMutations({increment:'JIA',decrement:'JIAN'}),
...mapActions({oddIncrement:'oddIncrement',waitIncrement:'waitIncrement'})
},
computed:{
...mapState(['sum','webName','language'])
}
}
</script>
<style>
button{
margin: 5px;
}
</style>
是不简单了好多。
组件间共享数据
vuex本来就是为了方便管理数据与方便组件间通信的。现在我们来实现组件间共享数据。
我们再来写一个组件PersonList,用他来展示一些人的数据。并且数据保存在vuex中。
const state={
sum:0,
webName:'稀土掘金',
language:'vuex',
persons:[
{name:'张三',age:18},
{name:'李四',age:19}
]
}
下面是PersonList组件
<template>
<div>
<h2>PersonList组件</h2>
<ul>
<li v-for='p in $store.state.persons' :key=p.index>{{p.name}}--{{p.age}}</li>
</ul>
</div>
</template>
<script>
export default {
name:'PersonList'
}
</script>
<style>
</style>
在页面的效果,(记得在App组件中呈现,这里就不写了)
接下来我们实现两个功能,添加人员与显示上方组件的求和信息。
<template>
<div>
<h2>PersonList组件</h2>
<input type="text" placeholder="请输入名字" v-model="name">
<input type="text" placeholder="请输入年龄" v-model="age">
<button @click='add'>提交</button>
<ul>
<li v-for='p in persons' :key=p.index>{{p.name}}--{{p.age}}</li>
</ul>
<h2>上方组件的求和为:{{sum}}</h2>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
name:'PersonList',
data(){
return{
name:'',
age:0
}
},
methods:{
add(){
const personObj={name:this.name,age:this.age}
this.$store.commit('addPerson',personObj)
}
},
computed:{
...mapState(['sum','persons'])
}
}
</script>
<style>
</style>
实现啦
我是小白,如有问题欢迎大家指出错误。