vuex学习笔记

来源:互联网 发布:应聘淘宝客服被骗 编辑:程序博客网 时间:2024/05/21 06:26
vuex应用的核心就是store(仓库),仓库中包含着应用中大部分的状态(state)。1. vuex的状态是响应式的,当vue组件从store中读取状态时,若store的状态发生变化,那么相应的组件也会相应地得到高效的更新。2. 不能直接改变store中的状态。改变store中的状态唯一途径就是显式地提交(commit) mutations。
创建state实例const store = new Vuex.Store({  state: {    count: 0  },  mutations: {    increment (state) {      state.count++    }  }})

现在,通过store.state就可以获取 状态对象,以及通过store.commit方法触发状态变更:

store.commit('increment')console.log(store.state.count) => 1

我们是通过提交mutation的方式,而非直接改变store.state.count。这样可以更明确地追踪到状态的变化,也让我们更有机会去实现一些能记录每次状态改变,保存状态快照的调试工具。实现如时间穿梭般的体验。


一.state

vuex使用单一状态树,用一个对象就包括了全部的应用层级状态,每个应用将紧紧包含一个stroe实例。单一状态树让我们能够直接定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用的状态快照。(时间穿梭于始终。)单状态数跟模块化并不冲突,能实现将状态和状态变更事件分布于各个子模块中。

vue通过stroe选项,将状态从根组件【注入】到每一个子组件中

const app = new Vue({    el:'#app',    store,    compents:{counter},    template:`        <div class = 'app'>            <counter></counter>        <div>    `})

以上代码在根实例中注册了store选项,该store实例会注入到根组件下的所有子组件中,且子组件能通过this.$store访问到。

const counter = {    template:`<div>{{count}}</div>`,    computed:{        count(){            return this.$store.state.count        }    }}如上,子组件counter中的计算属性获取了store实例

当需要获取多个状态时候,不必声明多个计算属性。
可以使用mapState辅助函数来帮助我们生成计算属性

import {mapState} from 'vuex'export default {    computed:mapState({        count: state => state.count,        countAlias: 'count',        countPlusLocalState(state){            return state.count + this.localCount        }    })}

使用vuex并不意味着需要将所有的状态放入vuex。如果有些状态严格属于某个单组件,最好还是作为组件的局部状态。


二.Getters

有时候需要从store中的state中派生出一些状态,例如对列表进行过滤并计数:

computed:{    doneTodosCount(){        return this.$store.state.todos.filter(todo => todo.done).length    }}

如果在多个子组件中都需要重复用到这个计算属性,那么就必须在每个子组件中都复制粘贴这个计算属性。
在vuex在store实例中定义了getters(可以认为是store的计算属性),那么子组件想要计算如上情况时,就只需要寻找在挂载在根实例上的store中的getters就可以了。
(store中的getters类似于vue实例的computed)
如下vuex实例:

const store = new Vuex({    state:{        todos:{            {id: 1,text: '...',done: true},            {id: 2,text: '...',done: false}        }    },    getters: {        doneTodos: state => {            return state.todos.filter(todo => todo.done)        }    }})可以看到,getters中进行了有关state的计算。因此所有的子组件都可以直接从根组件的store.getters得到“计算属性”

在组件中的使用如下:

computed:{    doneTodosCount () {        //通过获取从根组件上传来的stroe的对象的getters属性        return this.$store.getters.doneTodesCount    }   }

三.mutations

更改store中的状态的唯一方法是提交 mutation。mutations类似于事件,每一个mutation都有一个事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方。

  1. 要唤醒一个mutation handler,使用相应的type调用store.commit方法:

    const store = new Vuex.Store({    state: {        count: 1    },    mutations: {        increment (state) {            //变更状态            state.count++        }    }})store.commit('increment') //increment调用commit
  2. 可以向commit中传入额外的参数,即mutation的载荷(payload),一般是一个对象,可以包含多个字段并且易读。

    //···mutations: {    increment: (state, payload){        state.count += payload.amount    }}store.commit('increment',{    amount: 10})//另一种风格是直接使用包含type属性的对象:store.commit({    type: 'increment',    amount: 10})
  3. mutation必须是同步函数。
    任何在回调函数中进行的状态的改变都是不可追踪的

  4. 在组件中提交mutations时,可以使用this.$store.commit(xxx) 提交mutation,或者使用mapMutations辅助函数将组件中 的methods映射为store.commit 调用

    import { mapMuations } from 'vuex'export default {    //···    methods: {        ...mapMutations([            'increment' //映射 this.increment() 为this.$store.commit('increment')    ]),        ...mapMutations([            add: 'increment' //映射this.add()为this.$store.commit('increment')        ])    }}

四.Actions

Actions类似于mutations,不同在于

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

Actions函数接受一个与store实例具有相同方法和属性的context对象。一般通过es6中的 参数解构来优化代码

actions:{    increment ({ commit }) {        commit( 'increment' )    }}
  1. 分发 Action
    Action通过store.dispatch方法触发:

    store.dispatch('increment')

    之所以不直接commit mutation是因为mutation 必须是同步执行的。
    于是使用dispatch分发actions,就可以在action中进行异步操作了

  2. Action的分发方式跟mutation的commit方式一样

    //载荷方式store.dispatch('increment',{    amount: 10})//对象方式store.dispatch({    type: 'incrementAsync',    amount: 10 })
  3. actions实例,调用了异步api和分发多重mutations。通过提交mutations来记录action产生的副作用(即状态变更):

    actions: {    checkout ({commit, state},products) {            //把当前购物车的物品备份起来            const savedCartItems = [...state.cart.added]            //发出结账请求,然后乐观地清空购物车            commit(types.checkout_request)            //购物api接受一个成功回调函数和一个失败回调            shop.buyProducts(                products,                //成功操作                () => commit(types.checkout_success),                //失败操作                () => commit(types.checkout_failure,savedCartItems)            )    }}
  4. 在组件中分发patch
    你在组件中使用 this.$store.dispatch(‘xxx’) 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):

    import { mapActions } from 'vuex'export default {  // ...  methods: {    ...mapActions([      'increment' // 映射 this.increment() 为 this.$store.dispatch('increment')    ]),    ...mapActions({      add: 'increment' // 映射 this.add() 为 this.$store.dispatch('increment')    })  }}
  5. 组合actions
    action通常是异步的,要想处理更加复杂的异步流程,需要组合多个action。可以让store.dispatch处理被触发的action回调函数返回promise,并且dispatch仍旧返回promise。

    actions: {    actionA ({ commit }) {        return new Promise( (resolve, reject) => {            setTimeout(() => {                commit('someMutation')                resolve()            }        },1000)    })      }//dispatch返回的是promise

    现在就可以处理actionA返回来的promise

    store.dispatch('actionA').then(() => {    //...})

    在另一个action中也可以

    actions: {//...    actionB( {dispatch, commit}) {        return dispatch('actionA').then( () => {            commit('someOtherMutation')        })    }}//以此来实现组合多个actions 

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


原创粉丝点击