vuex 快速上手与原理浅析
概念
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (数据)
作用
将路由,组件等内部散乱的状态(数据)统一管理,方便在合适的场景被使用。
优势
相对于全局变量存储有何优势?
- 响应式
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
- 可跟踪
你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
使用
通过一个行程列表展示,查看行程详情的例子了解 vuex 的具用法。
安装
推荐
npm install vuex --save
vue 引入 vuex
// main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'
new Vue({
store,
render: h => h(App),
}).$mount('#app')
状态,方法定义
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
let store = new Vuex.Store({
state: {
orders: [],
curOrder: {
start: "",
end: ""
}
},
getters: {
},
mutations: {
setOrderList(state, data) {
state.orders = data
},
setCurOrder(state, data) {
state.curOrder = data
}
},
actions: {
async getList({
commit
}, params) {
let data = await axios.get("path/orders", {
params
})
commit('setOrderList', data)
}
}
});
export default store
vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态,每个应用将仅仅包含一个 store 实例,简单理解就是上面的 store.js
- state
用于定义和存储状态,例如 orders 存放行程列表,curOrder 存放当前选中的行程。
- mutations
更改 state 的唯一方法是提交 mutation,例如 setOrderList,修改 行程列表数据。
- actions
Action 类似于 mutation,但是不能直接修改状态,需要通过 mutations 间接修改,Action 可以包含任意异步操作。
应用使用 vuex
// list.vue
<template>
<div @click="goDetail(item)" v-for="item in list">
<div>起点:{{item.start}}</div>
<div>终点:{{item.end}}</div>
</div>
</template>
<script>
import { mapMutations, mapActions, mapState } from "vuex"
export default {
data() {
return {
}
},
computed: {
...mapState([
"list"
])
},
methods: {
...mapMutations(["setCurOrder"]),
...mapActions(["getList"]),
goDetail(item) {
this.setCurOrder(item);
// to detail 页面
}
},
created() {
this.getList();
}
}
</script>
- mapState state 辅助函数
mapState 函数返回的是一个对象,使用对象展开运算符,将 state 合并到当前组件的 computed 中,使用 state 就像使用 computed 一样容易。
- mapActions actions 辅助函数
mapActions 函数将 vuex 中定义的 actions 引入到当前组件 methods 中,需要获取数据时像调用普通方法一样,由于 getList 已经自动将获取的数据 orders 通过 setOrderList 存储到 state 中,所以在页面中可以直接使用 orders。
- mapMutations mutations 辅助函数
mapMutations 将 vuex 中定义的 mutations 引入到 methods 中,当前点击需要查看详情的行程时,通过 setCurOrder 将选中行程放入 curOrder 中。
// detail.vue
<template>
<div>
<div>起点:{{curOrder.start}}</div>
<div>终点:{{curOrder.end}}</div>
</div>
</template>
<script>
import { mapGetters, mapActions, mapState } from "vuex"
export default {
data() {
return {
}
},
computed: {
...mapState([
'curOrder'
])
}
}
</script>
当通过路由跳转到 detail 详情页时,通过 curOrder 直接获取列表页中已经存储的数据。
原理解析
Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,重新渲染Vue Components,界面随之更新
vue 装载 vuex
vue.use(vuex)
const install= (_vue)=>{
Vue = _vue
Vue.mixin({ beforeCreate() {
if(this.$options.store){
Vue.prototype.$store = this.$options.store
}
} })
}
执行 vue.use 会调用 vuex 的 install 方法,使用 vue 实例可以方便使用 this.$store 调用 vuex 的 api
vuex 中 state 定义
constructor(options){
this._vm = new Vue({
data:{
$$state:options.state,
}
});
this._committing = false;
this._actions = options.actions;
this.commit = this.commit.bind(this);
this.dispatch = this.dispatch.bind(this);
}
通过 vue 的 data 将 state 数据赋予响应式
commit 方法
commit(type,payload){
const entry = this._mutations[type]
if(entry){
entry(this.state,payload)
}
}
commit 方法传入 mutations 中已经定义的 type 值调用对应的方法并传入指定的参数
dispatch 方法
dispatch(type,payload){
const entry = this._actions[type]
if(entry){
entry(this.state,payload)
}
}
dispatch 方法传入 actions 中已经定义的 type 值调用对应的方法并传入指定的参数
控制 state 不被恶意使用
get state(){
return this._vm._data.$$state;
}
set state(v){
if(!this._committing){
console.error("不能直接使用",v)
}
}
state 只能被获取无法被外界赋值,只能通过 mutations 修改。
总结
这就是 vuex 的基本使用和原理浅析。
文中未讲到的内容例如 Module,后续补充敬请留意。