vuex学习笔记

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才会执行


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值