當面試被問到vuex的實現原理,你要怎麼回答?以下這篇文章就來帶大家深入了解vuex的實作原理,希望對大家有幫助!
關於vuex
就不再贅述,簡單回顧一下:當應用程式碰到多個元件共享狀態
時,簡單的單向資料流
很容易被破壞:第一,多個視圖依賴相同狀態;第二,來自不同視圖的行為需要變更相同狀態。若解決前者使用傳參的方式,則不適用於多層嵌套的組件以及兄弟組件;若解決後者使用父子組件直接引用或事件變更和同步狀態的多份拷貝,則不利於代碼維護。
所以,最好的方法是:把元件的共享狀態抽出,以一個全域單例模式管理!這也正是vuex
背後的基本想法。
所以,vuex的大致框架如下:
class Store { constructor() { // state // getters // mutations // actions } // commit // dipatch }
接下來,就寫寫看。
vue create vue2-vuex//创建vue2项目 yarn add vuex@next --save//安装vuex yarn serve//启动项目
1、State
#(1)使用
<pre class="brush:js;toolbar:false;">//store.js
// 仓库
import Vue from &#39;vue&#39;
import Vuex from &#39;vuex&#39;
import extra from &#39;./extra.js&#39;
Vue.use(Vuex) //引入vuex的方式,说明Store需要install方法
export default new Vuex.Store({
// 仓库数据源
state: {
count: 1,
dowhat: &#39;addCount&#39;
},
}</pre><pre class="brush:js;toolbar:false;">//app.vue
<template>
<div class="testState">
<p>{{mycount}}</p>
<p>{{dowhat}}:{{count}}</p>
</div>
</template>
<script>
export default {
import {
mapState
} from &#39;vuex&#39;
// 推荐方式
computed: mapState()({
mycount: state => state.count
}),
// 推荐方式的简写方式
computed: {
// 解构的是getters
...mapState([&#39;count&#39;, &#39;dowhat&#39;])
},
}
</script></pre>
由於Vuex 的狀態儲存是響應式的,從store實例中讀取狀態最簡單的方法就是在
計算屬性
中傳回某個狀態,這種模式
。在模組化的建置系統中,在每個需要使用state 的元件中需要頻繁地導入,並且在測試元件時需要模擬狀態Vuex 通過
store 選項,提供了一種機制將狀態從根元件「注入」到每一個子元件中(需呼叫Vue.use(Vuex)
)
所以除了Store
內部的五大屬性以外,還需要考慮外掛程式的一個install
方法,所以大致框架如下:<pre class="brush:js;toolbar:false;">class Store {
constructor() {
// state
// getters
// mutations
// actions
//modules
}
// commit
// dipatch
}
let Vuex = {
Store,
Install
}
export default Vuex</pre>
所以,接下來就可以具體實現了,<pre class="brush:js;toolbar:false;">class Store {
constructor(options) {
// state
this.state = options.state
}
}
let install = function(_Vue) {
_Vue.mixin({
beforeCreate() { //在组件创建之前自动调用,每个组件都有这个钩子
if (this.$options && this.$options.store) { //this.$options读取根组件
this.$store = this.$options.store
} else {
this.$store = this.$parent && this.$parent.$store
}
}
})
}</pre>
然而,上述的state的實作有一個缺點:當改變資料的時候,state
的資料不能動態的渲染。所以如何把state
裡的資料變成響應式成為關鍵問題?實際上,類似
裡的data,也可以透過這種方式讓其成為響應式。那就得從install方法傳入
Vue#,所以改變後:let Vue=null
class Store {
constructor(options) {
// state
this.vm = new _Vue({
data: {
state: options.state//data中的数据才是响应式
}
})
}
get state() {
return this.vm.state
}
}
let install = function(_Vue) {//用于Vue.use(plugin)
Vue=_Vue
_Vue.mixin({
onBeforeCreate() { //在组件创建之前自动调用,每个组件都有这个钩子
if (this.$options && this.$options.store) { //this.$options读取根组件
this.$store = this.$options.store
} else {
this.$store = this.$parent && this.$parent.$store
}
}
})
}
2、getters
##(1)使用
//store.js export default new Vuex.Store({ // 计算属性 getters: { // 这里的函数不需要调用,可以直接使用,官方默认前面有get getCount(state) {//接受 state 作为其第一个参数 return state.count * 100; } }, }(2)注意
有時我們需要從store 中的state 衍生出一些狀態(例如增加,刪除,過濾等等),Vuex 允許我們在store 中定義「getter」(可以認為是store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,並且只有當它的依賴值發生了改變才會被重新計算,Getter 接受state 作為其第一個參數,getter 在通過方法訪問時,每次都會去進行調用,而不會緩存結果##(3)實現
#// getters let getters = options.getters || {} this.getters = {} Object.keys(getters).forEach(getterName => { Object.defineProperty(this.getters, getterName, { get: () => { return getters[getterName](this.state) } }) })
3、mutations
(1)使用
//store.js
export default new Vuex.Store({
// 相当于methods
mutations: {
// mutations内部的函数,天生具备一个形参
add(state, n) {
state.count += n;
},
decrease(state, n) {
state.count -= n;
}
},
}
methods: {
submit() {
console.log('success');
},
// 解构仓库mutations里面的方法,要啥解构啥
...mapMutations(['add', 'decrease']),
// this.$store.commit('add'),
...mapActions(['addAction', 'decreaseAction']),
// this.addAction()调用actions里面的方法
// this.$store.dispatch('add'),
}
#(2)注意更改Vuex 的store 中的狀態的唯一方法是提交mutation。 Vuex 中的 mutation 類似於事件:每個 mutation 都有一個字串的 事件類型 (type) 和 一個
。這個回呼函數就是進行狀態變更的地方,而且它會接受 state 作為第一個參數,不能直接呼叫一個 mutation handler。這個選項更像是事件註冊:「當觸發一個類型為increment
的mutation 時,呼叫此函數。」要喚醒一個mutation handler,你需要以對應的type 呼叫store.commit 方法
可以向store.commit 傳入額外的參數,即mutation 的
負載(payload),在大多數情況下,負載應該是一個對象,這樣可以包含多個欄位且記錄的mutation 會更易讀(3)實作
// mutations let mutations = options.mutations || {} this.mutations = {} Object.keys(mutations).forEach(mutationName => { this.mutations[mutationName] = (arg) => {//保证多个(第二个)参数的传入 mutations[mutationName](this.state, arg) } }) commit = (method, arg) => {//使用箭头函数改变被调用的this的指向 // console.log(this); this.mutations[method](arg) }
4、actions
#(1)使用######
//store.js export default new Vuex.Store({ actions: { addAction(context) { // 在这里调用add方法 context.commit('add', 10); }, decreaseAction({ commit }) { commit('decreaseAction', 5) } }, }######(2)注意#######
store.dispatch
方法触发store.dispatch
可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch
仍旧返回 Promisestore.dispatch
在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行(3)实现
// actions let actions = options.actions || {} this.actions = {} Object.keys(actions).forEach(actionName => { this.actions[actionName] = (arg) => { actions[actionName](this, arg) } }) dispatch=(method, arg) =>{ this.actions[method](arg) }
5、modules
(1)使用
// actions let actions = options.actions || {} this.actions = {} Object.keys(actions).forEach(actionName => { this.actions[actionName] = (arg) => { actions[actionName](this, arg) } }) dispatch=(method, arg) =>{ this.actions[method](arg) }
//store.js modules: { extra: extra }
(2)注意
context.state
暴露出来,根节点状态则为 context.rootState
对于模块内部的 getter,根节点状态(rootState)会作为第三个参数暴露出来
let Vue = null//全局的_Vue class Store { constructor (options) { // state //this.state = options.state 写法不完美,当改变数据的时候,不能动态的渲染,所以需要把data中的数据做成响应式的 this.vm = new _Vue({ data: { state: options.state//data中的数据才是响应式 } }) // getters let getters = options.getters || {} this.getters = {} Object.keys(getters).forEach(getterName => { Object.defineProperty(this.getters, getterName, { get: () => { return getters[getterName](this.state) } }) }) // mutations let mutations = options.mutations || {} this.mutations = {} Object.keys(mutations).forEach(mutationName => { this.mutations[mutationName] = (arg) => {//保证多个(第二个)参数的传入 mutations[mutationName](this.state, arg) } }) // actions let actions = options.actions || {} this.actions = {} Object.keys(actions).forEach(actionName => { this.actions[actionName] = (arg) => { actions[actionName](this, arg) } }) } dispatch=(method, arg) =>{ this.actions[method](arg) } commit = (method, arg) => { // console.log(this); this.mutations[method](arg) } get state() { return this.vm.state } } let install = function(_Vue) { Vue = _Vue Vue.mixin({ beforeCreate() {//在组件创建之前自动调用,每个组件都有这个钩子 if (this.$options && this.$options.store) { // this.$options读取到根组件 this.$store = this.$options.store } else { // //如果不是根组件的话,也把$store挂到上面,因为是树状组件 this.$store = this.$parent && this.$parent.$store } } }) } let Vuex = { Store, install } export default Vuex
以上是深入了解vuex的實現原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!