Vuex

797 阅读2分钟

not ending.....

Vuex官网

Vuex简介

Vuex是一个专为Vue.js应用程序开发的状态管理模式。
devtools extension:time-travel调试、状态快照导入导出等高级调试功能。
Vuex可解决多个组件共享状态。


当是小应用的时候可用,简单的状态管理,不用Vuex

var store = {
  debug: true,
  state: {
    message: 'Hello!'
  },
  setMessageAction (newValue) {
    if (this.debug) console.log('setMessageAction triggered with', newValue)
    this.state.message = newValue
  },
  clearMessageAction () {
    if (this.debug) console.log('clearMessageAction triggered')
    this.state.message = ''
  }
}

var vmA = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

var vmB = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

Vuex使用

var store = new Vuex.Store({
    states:{},
    getters:{},
    mutations{},
    actions{},
    module{}
});
//store.commit(mutations)
//store.dispatch(actions)

State

Vuex使用单一状态数。唯一数据源。

import {mapState} from 'vuex';
export default {
    computed:mapState({
        count:state=>state.count,
        //'count'等同于state=>state.count
        countAlias: 'count',
        //为了使用‘this’获取局部状态,必须使用常规函数
        countPlusLocalState(state){
            return state.count+this.localCount
        }
    })
}
//或者
computed:mapState([
    //映射this.count为store.state.count
    'count'
])
//或者
computed:{
    //使用...将此对象混入到外部对象中
    localComputed(){
        ...mapState({})
    }
}

Getter

getters:{
    doneTodos: state => {
        return state.todos.filter(todo => todo.done)
    },
    doneTodosCount:(state,getters)=>{
        return getters.doneTodos.length
    },
    //返回一个函数,给getter传参。在对store里的数组进行查询时非常有用
    getTodoById:(state)=>(id)=>{
        return state.todos.find(todo=>todo.id===id)
    }
}
//使用doneTodosCount
computed:{
    doneTodosCount(){
        return this.$store.getters.doneTodosCount
    }
}
//使用getTodoById
store.getters.getTodoById(2)//{id:2,text:'...',done:false}

mapGetters辅助函数

import {mapGetters} from 'vuex';
export default {
    computed:{
        ...mapGetters([
            'doneTodosCount',
            'anotherGetter'
        ])
        //给getter属性取别名
        mapGetters({
            doneCount:'doneTodosCount'
        })
    }
}

Mutation

更改Vuex的sotre中的状态唯一方式是提交mutation。

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
});
store.commit('increment')

mutations传参

mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10)

state,payload

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit('increment',{
    amout:10
})
//或者使用对象风格的提交方式
store.commit({
    type:'increment',
    amount:10
})

Mutation需遵守Vue的响应规则

  • 最好提前在store中初始化所需的属性
  • 当需要在对象上添加新属性时,应该用Vue.set(obj,'newProp',123)
    • 或用新对象替换老对象
    state.obj = {...state.ovj,newProp:123}
    

Mutation必须是同步函数 在组件中提交Mutation 在组件中用this.$store.commit('xxx')提交mutation, 或者用mapMutations辅助函数将组件中methods映射为store.commit调用(这需要在根节点注入store)

import {mapMutations} from 'vuex';
export default {
    methods:{
        ...mapMutations([
            // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
            'increment',
            // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
            'incrementBy'
        ]),
        ...mapMutations({
            // 将 `this.add()` 映射为 `this.$store.commit('increment')`
            add:'increment'
        })
    }
}

当在mutations中使用异步,会导致你的程序很难调试。 当调用了两个包含异步调用的mutation改变状态,无法确定什么时候回调和那个先回调。这就需要确保,mutation中都是同步的。

Action

Action类似于mutation,不同于

  • Action提交的是mutation,而不是直接变更状态
  • Aciton可以包含任意异步操作
const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment (state) {
            state.count++
        }
    },
    actions: {
        increment (context) {
            context.commit('increment')
        }
    }
})

Action接受一个与store实例具有相同方法和属性的context对象,因此可调用context.commit提交一个mutation,或者通过context.state和contex.getter来获取state和getters。

//或利用参数解构简化代码
actions:{
    increment({commit}){
        commit('increment')
    }
}

触发Aciton

store.dispatch('increment');
//带参数方式
store.dispatch('incrementAsync',{
    amount:10
})
//以对象方式
store.dispatch({
    type:'incrementAsync',
    amount:10
})

购物车实例

actions:{
    checkout({commit,state},products){
        //把当前购物车的物品备份起来
        const saveCardItems = [...state.cart.added];
        //发出结账请求,然后乐观地清空购物车
        commit(types.CHECKOUT_REQUEST);
        //购物API接收一个成功回调和一个失败回调
        shop.buyProducts(
            products,
            () => commit(types.CHECKOUT_SUCCESS),
            // 失败操作
            () => commit(types.CHECKOUT_FAILURE, savedCartItems)
        )
    }
}

以上,通过提交mutation记录action产生的副作用(即状态变更) mapActions

import { mapActions } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

组合Action 即异步+异步

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
//调用
store.dispatch('actionA').then(() => {
  // ...
})
//或在另外一个action中也可
actions: {
  // ...
  actionB({dispatch,commit}){
      return dispatch('actionA').then(()=>{
        commmit('someOtherMutation')
      })
  }
}

结合async/await

//假设getData()和getOtherData()返回的是Promise
actions:{
    async actionA({commit}){
        commit('getData',await getData())
    },
    async actionB({dipatch,commit}){
        await dispatch('actionA')//等待actionA完成
        commit('getOtherData',await getOtherData())
    }
}

一个store.dispatch在不同模块下可触发多个action函数,在这种情况下,只有当所有触发函数完成后,返回的Promise才会执行。??

Module

Vuex允许将store分割成模块module。

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
};
const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
};
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

模块的局部状态 局部状态可用context.state暴露,根节点状态用context.rootState rootState

const moduleA = {
  // ...
  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

rootState

const moduleA = {
  // ...
  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }
}

not ending 命名空间 nameSpaced:true 默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的——这样使得多个模块能够对同一 mutation 或 action 作出响应。