簡易版Vuexソース実装
3959 ワード
Vuex使用
1、Vuexプラグインを登録する installメソッド を実装 Vueルートインスタンス化時に、storeオブジェクト をVueルートインスタンスにマウントする. store.stateとgetterはいずれもデータ応答式であり、直接変更できないstateとgetterの値はcommitとdispatch のみを通過する.はcommitを実現し、stateの値 を同期的に変更する.はdispatchを実現し、stateの値 を非同期で修正することをサポートする.
ソース実装 installメソッドを実行する場合、Vueを通過する.mixin混入方式は、Vueをインスタンス化する際、beforeCreateライフサイクルにおいて、VueプロトタイプにstoreオブジェクトVueをマウントする.prototype.$store = store Storeコンストラクション関数には、state、mutations、actions、gettersなどの を取得するのに便利なインポートされた構成オプションが保存されます. store.state実装:newによる新しいVueインスタンス_vm、stateを_に保存vm.data,stateは応答式データになる.stateのsetとgetを書き換え、stateの値を直接変更することを防止し、commitとdispatchでstateの値を変更するしかなく、getは_vm.data取得 commitメソッド実装:commitは、dispatch呼び出しがthis指向の変化であることを防止するために、thisをstoreインスタンスとしてバインドする必要がある.入力パラメータtypeによりmutationsから関数を取り出して実行し、stateパラメータ に入力する dispatchメソッド実装:commitメソッドと同様に、入力パラメータtypeによりactionsから関数を取り出して実行し、commitメソッドとstateをcontextに保存してパラメータとして に入力する. getters実装:gettersのプロパティを遍歴し、すべて_に変換vmのcomputedでは,無パラメータの高次関数を返し,Objectを用いる.definePropertyはkeyごとにgetメソッドを再定義し、setを定義する必要がなく、getterの値 を直接変更することを防止する.
1、Vuexプラグインを登録する
import Vuex from 'vuex'
Vue.use(Vuex)
2、Storeインスタンスの作成export default new Vuex.Store({
state: {
count: 0
},
mutations: {
add(state, payload) {
state.count += payload
}
},
actions: {
delayAdd(context, payload) {
setTimeout(() => {
context.commit("add", payload)
}, 1000)
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
}
})
3、Vueルートインスタンスへのマウントnew Vue({
render: h => h(App),
store
}).$mount('#app')
4、コンポーネントでの使用this.$store.state.count
this.$store.getters.doubleCount
this.$store.commit('add', 1)
this.$store.dispatch('')
まとめて、Vuexは以下のことをする必要があります.ソース実装
let Vue
class Store {
constructor(options) {
this._vm = null
this._mutations = options.mutations
this._actions = options.actions
this._wrappedGetters = options.getters
this.getters = {}
const storeComputed = {}
const self_store = this
Object.keys(this._wrappedGetters).forEach((key) => {
// getters
const gettersFn = self_store._wrappedGetters[key]
// computed,
storeComputed[key] = () => {
return gettersFn(self_store.state)
}
// getter ,
Object.defineProperty(self_store.getters, key, {
get: () => self_store._vm[key],
enumerable: true
})
})
// new Vue _vm, _vm
this._vm = new Vue({
data: {
$$state: options.state // $$ Vue
// Vue ,
},
computed: {
...storeComputed
}
})
console.log(this._vm)
}
get state () {
return this._vm._data.$$state
}
set state(v) {
throw new Error(`use store.replaceState() to explicit replace store state.`)
}
// this
// this.commit = this.commit.bind(this) this
commit = (type, payload) => {
// type mutations
const fn = this._mutations[type]
if (!fn) return
fn.call(this, this.state, payload)
}
dispatch = (type, payload) => {
// type actions
const fn = this._actions[type]
if (!fn) return
fn.call(this, {commit: this.commit, state: this.state}, payload)
}
}
function install(vue) {
/*
1、
2、 vue
3、 , store
*/
// 1、
if (Store.installed) {
return
}
Store.installed = true
//2、 vue
Vue = vue
// , store
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
},
})
}
export default { Store, install }
ソース実装の考え方