Vuex的基本原理和简单使用
什么是Vuex,有什么用?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
普通的Vue状态自管理在遇到多个视图共同依赖同一状态,或者会改变同一状态时,会遇到难以管理,难以维护的麻烦。为了解决这个麻烦,Vue官方基于全局单例模式提供了Vuex状态管理框架。
在Vuex框架中,Vue视图,状态,数据之间的关系如下图所示:
什么时候应该使用Vuex,什么时候不要使用?
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
如何使用Vuex
创建一个Vuex的状态管理仓库
- 安装Vuex框架:
我们通过如下命令为Vue项目中添加Vuex框架
npm i Vuex
如下图所示:
2. 在main.js中引入Vuex框架,并通过use命令加载到Vue中
import Vuex from 'vuex'
Vue.use(Vuex)
- 创建一个store仓库,并把store仓库注册到Vue全局中;store仓库包含state(单一状态树,提供响应式数据),getters(store的计算属性),mutations(改变store状态的方法),actions(处理异步操作,触发mutation)
const store = new Vuex.Store({
state:{
},
mutations:{
},
actions:{
},
getters:{
}
})
new Vue({
store,
render: h => h(App),
}).$mount('#app')
mutations
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数.
你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法
actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
- Action的分发使用关键字
- 为store仓库创建单一状态树State,并创建mutations方法修改state
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
actions:{
},
getters:{
}
})
- 到此为止,Vue中的组件就可以使用store状态仓库了。因为在main.js中,我们通过new Vue将store仓库注册到Vue全局中,所以我们在模板中可以通过this.$store的方式获取到我们store仓库。下面的示例展示了通过组件的计算属性computed定义count变量并通过模板语法展现store状态仓库中的count值。
<template>
<div id="app">
{{count}}
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
count(){
return this.$store.state.count
}
},
methods:{
}
}
效果如下:
6. 我们当然可以修改store的count值。我们先采用以前的模板事件来修改。
<template>
<div id="app">
{{count}}
<input type="button" @click="handleClick" value="Count++" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
count(){
return this.$store.state.count
}
},
methods:{
handleClick(){
return this.$store.state.count++;
}
}
}
</script>
效果如下:
7. 但是Vue并不鼓励我们采用这样的方式来修改store的count值。这样管理依然不方便,很有可能造成混乱。按照上面对mutations的介绍,我们可以猜到Vuex鼓励我们通过mutations对store的state进行修改,这样我们对state的修改过程才会被Vuex记录下来。我们先前在初始化state时,同步初始化了mutations:我们创建了一个叫increment的方法,现在我们只需要调用这个方法即可。每一个mutations中的方法本质都是一个回调函数,处理sate状态的逻辑都包含在里面,接收state参数。mutations方法可以多接收一个额外参数(提交荷载),如果希望传入多个数据,则应该组织成对象再传入(示例中仅仅是一个简单的number)
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
- Vuex中的mutations方法不能被直接调用,必须被actions或模板以commit的形式调用。我们先尝试使用模板直接commit的形式调用(假设我们没有异步操作需要处理,完全可以绕过actions)
<template>
<div id="app">
{{count}}
<input type="button" name="count2" @click="$store.commit('increment',2)" value="Count+2" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
count(){
return this.$store.state.count
}
},
methods:{
}
}
</script>
<style>
</style>
- 我们通过click事件直接对store进行了commit操作,commit调用时传入了两个参数,第一个是回调函数名:increment,另一个是提交荷载:一个整数;效果如下:
- 到此为止,我们一直是使用的Vue组件的compute属性展示的sotre。如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。先前介绍过:getters是sotre的computer,那么我们完全可以在sotre的getters中处理展示逻辑。
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
actions:{
},
getters:{
doubleCount(state){
return state.count * 2
}
}
})
<template>
<div id="app">
{{$store.getters.doubleCount}}
<input type="button" name="count2" @click="$store.commit('increment',2)" value="Count+2" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
},
methods:{
}
}
</script>
<style>
</style>
效果如下:
11. 我们一直还没有使用到store的actions。根据官网描述,actions与mutation很像,不同的是用来触发(commit)mutation而不是直接修改状态,最重要的是我们可以在actions中处理异步逻辑,调用远程API等等(如下示例中,利用模拟异步等待);前台调用是使用dispatch关键字调用。
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
increment(state,n){
state.count+=n
console.log(state.count)
}
},
actions:{
increment(state,n){
setTimeout(() => {
state.commit('increment',n)
},1000);
}
},
getters:{
doubleCount(state){
return state.count * 2
}
}
})
<template>
<div id="app">
{{$store.getters.doubleCount}}
<input type="button" name="count1" @click="$store.dispatch('increment',3)" value="Count+3" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
},
computed:{
},
methods:{
}
}
</script>
<style>
</style>
效果如下: