到目前爲止,咱們已經實現了vuex
中的getters
,mutations
,接下來就該輪到咱們的actions
了。
在具體實現actions
以前,咱們必須明確actions
的功能和用途.javascript
詳情能夠參考vuex-actionshtml
經過官網的介紹,咱們總結得出,在actions
中,咱們主要作兩件事,一件是commit mutaions
,另外一件是dispatch other actions
vue
爲了可以完成以上兩件任務,咱們必須使得在actions
中可以訪問到store
中的commit
和dispatch
方法。java
store
中這步操做和getters/mutations
中徹底同樣,有須要注意的地方在代碼中給出了註釋vuex
import Vue from 'Vue'
class Store{
constructor(options){
this._vm = new Vue({
data:options.state
})
...//getters
...// mutations
// actions
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach((key)=>{
this.actions[key] = (payload) =>{
actions[key](this,payload) // 在這裏傳入this使爲了讓咱們可以訪問到commit和dispatch方法
}
})
get state(){
return this._vm
}
// 在這裏,咱們實現一個dispatch方法
dispatch(actionType,payload){
this.actions[actionType](payload)
}
commit(mutationType,payload){
this.mutations[mutationType](payload)
}
}
複製代碼
接下來,讓咱們註冊一個簡單的actions
,ide
const store = new Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment ({commit,dispatch}) {
commit('increment')
}
},
getters:{
getCount(state){
return state.count
}
}
})
複製代碼
如今咱們注意一下,actions
中的increment
的執行流程函數
// options中的actions綁定到了store實例上
// actions['increment'](this) //執行
// {commit,dispatch} = this // 結構賦值
// commit('increment')
// this.mutations['increment'] 這裏會出現問題,this此時並非指`store`實例,而是指向undefined
複製代碼
this
指向類的方法內部若是含有this
,它默認指向類的實例。可是,必須很是當心,一旦單獨使用該方法,極可能報錯。測試
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
複製代碼
上面代碼中,printName
方法中的this
,默認指向Logger
類的實例。可是,若是將這個方法提取出來單獨使用,this
會指向該方法運行時所在的環境(因爲 class
內部是嚴格模式,因此 this
實際指向的是undefined
),從而致使找不到print
方法而報錯。ui
一個比較簡單的解決方法是,在構造方法中綁定this
,這樣就不會找不到print
方法了。this
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
// ...
}
複製代碼
另外一種解決方法是使用箭頭函數。
class Obj {
constructor() {
this.getThis = () => this;
}
}
const myObj = new Obj();
myObj.getThis() === myObj // true
複製代碼
箭頭函數內部的this
老是指向定義時所在的對象。上面代碼中,箭頭函數位於構造函數內部,它的定義生效的時候,是在構造函數執行的時候。這時,箭頭函數所在的運行環境,確定是實例對象,因此this
會老是指向實例對象。
所以咱們必須想辦法保障this
是指向store
實例的
在這裏,咱們將commit,dispatch
聲明爲箭頭函數,由於箭頭函數中的this
在創造時就被肯定了,而不會隨着上下文環境而發生變化。
dispatch = (actionType,payload) =>{
this.actions[actionType](payload)
}
commit = (mutationType,payload) =>{
this.mutations[mutationType](payload)
}
複製代碼
此時完整代碼爲
class Store {
constructor(options) {
this.data = options.state;
let getters = options.getters || {}
this.getters = {}
// mutations
let mutations = options.mutations || {}
this.mutations = {}
Object.keys(mutations).forEach((key) => {
this.mutations[key] = (payload) => {
mutations[key](this.state, payload)
}
})
// 把getter對象上的屬性所有綁定到this.getter上
Object.keys(getters).forEach((key) => {
Object.defineProperty(this.getters, key, {
get: () => getters[key](this.state)
})
})
let actions = options.actions || {}
this.actions = {}
Object.keys(actions).forEach((key) => {
this.actions[key] = (payload) => {
actions[key](this, payload) // 在這裏傳入this使爲了讓咱們可以訪問到commit和dispatch方法
}
})
}
get state() {
return this.data
}
dispatch = (actionType, payload) => {
this.actions[actionType](payload)
}
commit = (mutationType, payload) => {
this.mutations[mutationType](payload)
}
}
複製代碼
經過上面的代碼,咱們發如今實現getters
,mutations
,actions
的綁定時,邏輯都是同樣的,咱們能夠將其抽取出來,封裝成一個函數。
let forEach = (obj,callback)=>{
Object.key(obj).forEach(key=>{
callback(key,obj[key])
})
}
複製代碼
使用封裝函數,修改咱們的代碼:
let forEach = (obj,callback)=>{
Object.key(obj).forEach(key=>{
callback(key,obj[key])
})
}
class Store {
constructor(options) {
this.data = options.state;
let getters = options.getters || {}
this.getters = {}
// mutations
let mutations = options.mutations || {}
this.mutations = {}
forEach(getters,(key,fn)=>{
Object.defineProperty(this.getter,key)=>{
get:()=>{
return fn(this.state)
}
}
})
forEach(mutations,(key,fn)=>{
this.mutations[key] = (payload)=>{
fn((this.state, payload))
}
})
let actions = options.actions || {}
this.actions = {}
forEach(actions,(key,val)=>{
this.actions[key] = (payload)=>{
fn(this,payload)
}
})
}
get state() {
return this.data
}
dispatch = (actionType, payload) => {
this.actions[actionType](payload)
}
commit = (mutationType, payload) => {
this.mutations[mutationType](payload)
}
}
複製代碼
測試是否成功
store.dispatch('increment')
console.log(store.getters.getCount) // 輸出1 符合預期
複製代碼
未完待續...