vuex学习总结

state

  • 作用:相当于vue中的data,用于存储状态,是唯一数据源,而且是只读,不能做直接修改。从头开始学习Vuex
  • 语法:

const store = new Vuex.Store({
  state: {
    text:'hello world'
  }
})
  • 调用:

// 方法1
store.state.text
// 方法2(需要使用vue.use注入)
this.$store.state.text
// 方法3,通过辅助函数mapState
import { mapState } from 'vuex';
export default {
    computed: {
        // 使用ES6的扩展运算符来达到将state释放出来
        ...mapState([
          // 映射 this.text 为 store.state.text
          'text'
        ])
    }
}

注意:如果一般state初始化时最好就设置好所需属性,如果真的需要动态需改某一个属性,可以如下:
1)Vue.set(obj, 'newProp', 123)
2)state.obj = { ...state.obj, newProp: 123 }

getter

  • 作用:相当于vue中的computed,作用也是类似的。
  • 语法:

const store = new Vuex.Store({
  state: {
    text:'hello world'
  },
  getters: {
    // 第一个参数固定是state对象,第二个参数固定是getters对象
    getText: (state, getters) => {
        return state.text + ' xiaoming';
    },
    // getters方法中调用getters方法
    getGettersText: (state, getters) => {
        return getters.getText;
    },
    // getters方法返回一个函数
    getFuncText: (state,getters) => (name) => {
        return state.text + ' ' + name;
    }
  }
})
  • 调用:

// 方法1
store.getters.getText
// 方法2
this.$store.getters.getText
// 方法3,通过辅助函数mapGetters
import { mapGetters } from 'vuex'
export default {
    computed: {
        ...mapGetters([
            'getText',
            'getGettersText',
            'getFuncText'
        ])
    }
}

mutation

  • 作用:相当于vue中data对象的的set方法,是唯一可以改变state数据的方式,定位是同步改变,即在mutation的方法中不支持异步逻辑,这个的具体原因是因为mutation类似于事件监听的回调函数,而任何在回调函数中进行的状态的改变都是不可追踪的。
  • 语法:

const store = new Vuex.Store({
  state: {
    text:'hello world'
  },
  mutations: {
    // 第一个参数固定是state,剩下还可以再传入一个或0个参数(也叫载荷),这个载荷参数一般是对象,方便传入多个值
    changeText (state, payload) {
      // 变更状态
      state.text = 'welcome' + payload.name;
    }
  }
})
  • 调用:

// 方法1,只是第二个参数是载荷
store.commit('changeText', {
    name: 'xiaoye'
})
// 方法2,相当于整个对象都是载荷
store.commit({
    type: 'changeText',
    name: 'xiaoye'
})
// 方法3
this.$store.commit('changeText', {
    name: 'xiaoye'
})

// 方法4,依赖辅助函数mapMutations 
import { mapMutations } from 'vuex';
export default {
  methods: {
  // 将this.changeText({name: 'xiaoye'})映射为this.$store.commit('changeText', {name: 'xiaoye'});
    ...mapMutations([
      'changeText'
    })
  }
}

action

  • 作用:相当于vue中的method,不能直接修改state,只能通过调用mutation中的方法间接改变state,定位是异步改变,当然也可以同步,如果是需要异步改变的逻辑建议写在action中,其实用过action就知道,其实就相当于把本来属于vue中的method中的方法放到vuex中的action中来而已,只是说公共的异步请求不再用写那么多份在不同的method中,只需要写一份放在action中即可。
  • 语法:

const store = new Vuex.Store({
  state: {
    text:'hello world'
  },
  mutations: {
    // 第一个参数固定是state,剩下还可以再传入一个或0个参数(也叫载荷),这个载荷参数一般是对象,方便传入多个值
    changeText (state, payload) {
      // 变更状态
      state.text = 'welcome' + payload.name;
    }
  },
  actions: {
    // 第一个参数是固定的一个类似store的实例,具有和store实例相同方法和属性,即可以直接调用state,getters,commit,dispatch等;第二个参数同mutations一样,是载荷
    asynChangeText (context, payload) {
        setTimeout(() => {
          context.commit('changeText', payload.asynName)
        }, 1000)
    }
  }
})
  • 调用:

// 方法1
store.dispatch('asynChangeText', {
  asynName: 'xiaoMing'
})

// 方法2
store.dispatch({
  type: 'asynChangeText',
  asynName: 'xiaoMing'
})

// 方法3
this.$store.commit('asynChangeText', {
    asynName: 'xiaoMing'
})

// 方法4,依赖辅助函数mapActions
import { mapActions } from 'vuex';
export default {
  // 用法同 mutation 一样
  methods: {
    ...mapActions([
      'asynChangeText'
    })
  }
}

module

  • 作用:将state模块化和嵌套子模块化,避免state过大,而变得臃肿,不方便管理,每一个模块都包含完整的state、actions、mutations、getters。
  • 语法1(默认命名空间):

/**
 ** 模块化(默认命名空间)
 */
const moduleA = {
  state: {
    a: 1,
  },
  mutations: {
    // 该state包含的是本模块自己以及子模块的state
    setA (state, payload) {}
  },
  actions: {
    // 该context除包含本模块自己以及子模块的属性和方法外,还另外多包含rootGetters和rootState两个属性根模块(moduleA)的state和getter
     getAsynA (context, payload) {}
  },
  getters: {
    // 这里的rootState和rootGetter等同于根模块(moduleA)的state和getter
    getA (state, getters, rootState, rootGetter) {}
  },
  // 两个子模块
  modules: {
    moduleB,
    moduleC
  }
}

// 和moduleA模块一样,只是rootState和rootGetter依然表示moduleA这个跟模块而已
const moduleB = {
  state: {  },
  mutations: { ... },
  actions: { ... }
}
// 同moduleB
const moduleC = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store(moduleA)

注意:在默认的命名空间中:
1)所有的模块和子模块的mutations和actions都是包含在全局中的,也叫在全局命名空间中。也就是说如果不同的模块中有相同的actions或者mutations是会存在重复注册挂载到全局中的情况的,只不过他们不是覆盖而是追加的关系而已,被调用的顺讯也是按照模块的注册顺序递归调用的。

2)所有模块和子模块的getters都是包含在全局中的,不过不同的是如果出现不同模块之间重名的情况,不是追加而是先到先得,即哪一个模块先注册,即使用谁的。

3)而state是仍然是划分模块的,外部如果要调用,调用方式也是按照模块的层级路径来调用的。即:moduleA的状态:store.state;moduleB的状态:store.state.moduleB

  • 调用:

// 调用state,方法1
store.state.a
store.state.moduleB.b
// 调用state,方法2
this.$store.state.a
this.$store.state.moduleB.b
// 调用state,方法3
import {mapState} from 'vuex';
export default {
    computed: {
        ...mapState([
            'a',        // 是moduleA的state
            'moduleB',   // moduleB是一个对象,包含自己以及子模块的state
            'c': state => state.a.moduleC.c // moduleC模块下的state可以通过这种方法的形式返回值
        ])
    }
}

// 调用getter,方法1
store.getters.getA
store.getters.getB
// 调用getter,方法2
this.$store.getters.getA
this.$store.getters.getB
// 调用getter,方法3
import { mapGetters } from 'vuex'
export default {
    computed: {
        ...mapGetters([
            'getA',
            'getB'
        ])
    }
}

// 调用mutations,方法1,和getter相同点都是挂载在全局中,不同点是不同模块中存在相同名称是会按顺序触发的
store.commit('setA')
store.commit('setB')
// 调用mutations,方法2
store.commit({
    type: 'setA'
})
// 调用mutations,方法3
this.$store.commit('setA')
// 调用mutations,方法4
import { mapMutations } from 'vuex';
export default {
  methods: {
    ...mapMutations([
      'setA'
    })
  }
}

// 调用actions,同mutations一样
  • 语法2(命名空间):

/**
 ** 模块化(命名空间)
 */
const moduleA = {
  namespaced: true,
  state: {
    a: 1,
  },
  mutations: {
    // 该state包含的是本模块自己以及子模块的state
    setA (state, payload) {}
  },
  actions: {
    // 该context除包含本模块自己以及子模块的属性和方法外,还另外多包含rootGetters和rootState两个属性根模块(moduleA)的state和getter
     getAsynA (context, payload) {}
  },
  getters: {
    // 这里的rootState和rootGetter等同于根模块(moduleA)的state和getter
    getA (state, getters, rootState, rootGetter) {}
  },
  // 两个子模块
  modules: {
    moduleB,
    moduleC
  }
}

// 和moduleA模块一样,只是rootState和rootGetter依然表示moduleA这个跟模块而已
const moduleB = {
  //  namespaced: true, // 这里如果不设置命名空间的话那moduleC就继承父命名空间
  state: {  },
  mutations: { ... },
  actions: { ... }
}
// 同moduleB
const moduleC = {
  namespaced: true,
  state: { ... },
  mutations: { ... },
  actions: { ... },
  modules: {
        moduleD: {
            namespaced: true,
            state: {
                d: 1,
            },
            mutations: {},
            actions: {}
        }
    }
}

const store = new Vuex.Store(moduleA)

注意:在命名空间中:
1)所有的模块和子模块的mutations、actions、getters都是包含在各自的命名空间或父命名空间中,即自动根据模块注册的路径调整命名

2)而state不受影响,因为默认state也已经是层级嵌套的了。

  • 调用

// 调用state,方法4(前三个方法和默认命名空间类似)
computed: {
  ...mapState('moduleC/moduleD', {
    d: state => state.d
  }),
  ...mapState('moduleC/moduleD', ['d']) // 这两种是一样的,只是写法不同
},
// 调用state,方法5(通过辅助函数createNamespacedHelpers)
import { createNamespacedHelpers } from 'vuex';
const { mapState } = createNamespacedHelpers('moduleC/moduleD');
export default {
  computed: {
    // 在 `moduleC/moduleD` 中查找
    ...mapState({
      d: state => state.d
    })
  }
}

// 其他的getter、mutations、actions也是和state类似的以上的方法

plugins

  • 作用:plugins 是vuex中的一个函数,一般配合 subscribe 函数实现类似于拦截器的效果,而且是一个成功之后的拦截器,是每次 mutation 调用成功之后的钩子,它接收store 实例作为作为唯一的参数。
  • 语法:

const myPlugin = store => {
    // mutation 的格式为:{ type, payload },通过这个对象可以判断是哪一个 mutation 被调用了,额外的参数是什么。
    store.subscribe((mutation, state) => {
        if (mutation.type === 'updateA') {
            console.log(mutation)
            console.log(state)
        }
    })
}
const moduleA = {
    state: {
        a: 1,
    },
    mutations: {
        // 被调用完成之后会触发 myPlugin 中的 subscribe 回调
        updateA (context, payload) {
            console.log('A')
        }
    },
    actions: {...},
    getters: {...},
    modules: {...},
    plugins: [myPlugin]
}

export default new Vuex.Store(moduleA);

注意:在插件中如果要修改state状态,也需要通过store调用commit,从而触发 mutation 改变state的状态,也就是说不能直接修改state状态。

strict

  • 上面一直强调就是修改只能在 mutations 中完成,为了强制约束,可是在vuex实例化的时候传入该属性(严格模式)。
  • 语法

const moduleA = {
    state: {...},
    mutations: {...},
    actions: {...},
    getters: {...},
    modules: {...},
    plugins: [...],
    strict: true
}

export default new Vuex.Store(moduleA);

原文地址:https://segmentfault.com/a/1190000013133924

posted @ 2018-11-07 16:56  sfornt  阅读(508)  评论(0编辑  收藏  举报