Vue 生态篇(一)

用户头像
shirley
关注
发布于: 2020 年 06 月 01 日

为什么需要Vuex

单向数据流

整个系统运行是一个单向的,数据State去驱动视图View的更新,用户在视图View上进行一些操作触发Actions,通过Actions的方式再去更改数据State

状态管理

下图组件E、F、I都需要显示用户名称userName,当这个名称被修改时,这些组件都需要同步更新userName,那如何进行userName状态管理呢?

方式一:通过组件层层传递方式,在组件E、F、I的共同父组件A上进行管理。这种方式比较脆弱,而且成本比较高。

方案一示例

方式二:Provide/Inject,避免了层层传递的繁琐,但它还是与组件强相关,需要在组件中提供数据,对于小型状态管理是个不错的方案,但当状态数比较大时,需要一个更加系统化的状态管理工具。

方式三:Vuex,不仅仅是提供响应式数据,还可以动态注册响应式数据,用命名空间来管理数据,通过插件记录数据的更改便于调试。

Vuex运行机制

下图绿色框中是Vuex要做的事情,它不再与组件强相关,可以独立提供响应式数据

Vuex整个运行机制也是个单向数据流



Vuex提供数据State来驱动视图组件Vue Components,视图组件通过Dispatch来派发Actions。在Actions中可以进一步做些异步操作(如Backend API请求后端接口),然后通过Commit形式提交给Mutations,Mutations最终来更改数据State。经过一层Mutations,主要是为了在插件Devtools中记录数据的变化,这样可以在插件Devtools中进行调试。整个过程中,Mutations是纯同步操作到Devtools,异步操作需要在Actions中进行,如果没有异步操作,可以直接从视图组件Commit到Mutations。

Vuex运行机制

如何在Vue中使用Vuex

state:数据是响应式的

getters:类似于组件中的计算属性,方便缓存某个数据

Vuex的acitons应该避免直接操作state,state的更改应该由mutations去修改,不然vue-devtools插件记录不到state的变更。actions可以更具当前state进一步处理数据,计算或请求后端接口,然后通过commit的形式提交给mutations去处理。

action函数接受一个与 store 实例具有相同方法和属性的 context 对象。

//main.js
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0,
},
mutations: {
increment(state) {
state.count++
}
},
/**
* action函数接受一个与 store 实例具有相同方法和属性的 context 对象
* increment 里的传的参数是context,注意commit两边的大括号,
* 它的作用就是从context里面取出来 commit,也是es6的语法。
*/
actions: {
increment({commit}) {
setTimeout(()=>{
// state.count++ // 不要对state进行更改操作,应该通过commit交给mutations去处理
commit('increment')
}, 3000)
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
new Vue({
store,
render: h => h(App),
}).$mount('#app')



//App.vue
<template>
<div id="app">
{{count}}
<br>
{{$store.getters.doubleCount}}
<button @click="$store.commit('increment')">count++</button>
<button @click="$store.dispatch('increment')">count++</button>
</div>
</template>
<script>
export default {
name: 'app',
computed: {
count() {
return this.$store.state.count
}
}
}
</script>



Vuex核心概念及底层原理

  • State —— this.$store.state.xxx 取值

提供一个响应式数据

  • Getter —— this.$store.getters.xxx 取值

借助Vue的计算属性computed来实现缓存

  • Mutation —— this.$store.commit(“xxx”) 赋值

更改state方法

  • Action —— this.$store.dispatch(“xxx”) 赋值

触发mutation方法不能直接修改值,还是需要commit

  • Module 模块化,状态辅助管理。Vue.set动态添加state到响应式数据中。

import Vue from 'vue'
const Store = function Store (options = {}) {
const {state = {}, mutations={}} = options
this._vm = new Vue({
data: {
$$state: state
},
})
this._mutations = mutations
}
Store.prototype.commit = function(type, payload){
if(this._mutations[type]) {
this._mutations[type](this.state, payload)
}
}
Object.defineProperties(Store.prototype, {
state: {
get: function(){
return this._vm._data.$$state
}
}
});
export default {Store}



Store 是如何做到我们的一个响应式的?

实际上它还是利用了 Vue,通过 new Vue() 函数构建了一个 Vue 实例,并将 state 存放在了这个实例的响应式数据 data里面。这样的话,state 已经变成了一个间接的响应式数据。



通过Object.defineProperties(Store.prototype, {......})重写了state的getter函数。get 函数返回一个 _vm 实例下的数据 data 中的 $$state 属性,其实就是 Store 对象下的 state 对象,只不过从 _vm 实例中取了一遍,就编程响应式的了。



Vuex最佳实践

核心概念

  • State —— this.$store.state.xxx 取值 —— mapState 取值

  • Getter —— this.$store.getters.xxx 取值 —— mapGetter 取值

  • Mutation —— this.$store.commit(“xxx”) —— mapMutations 赋值

  • Action —— this.$store.dispatch(“xxx”) 赋值 —— mapAction 赋值

  • Module 模块化,状态辅助管理。

Module

  • 开启命名空间 namespaced:true

  • 潜逃模版不要过深,尽量扁平化

  • 灵活应用 createNamespacedHelpers

使用常量替代 Mutation 事件类型

使用常量替代 Mutation 事件类型



用户头像

shirley

关注

还未添加个人签名 2019.04.02 加入

还未添加个人简介

评论

发布
暂无评论
Vue生态篇(一)