【Vue】Vue相关生态——Vuex

Vue相关生态——Vuex

    • 与全局对象的区别
  • State
  • Getter
  • Mutation
  • Action
  • Module
  • 项目结构
  • 组合式API

#基本概念

与全局对象的区别

Vuex 和单纯的全局对象有以下两点不同:

  • Vuex的状态存储是响应式的,当vue组件从store中读取状态时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效的更新
  • 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

State

单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。

这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。

单状态树和模块化并不冲突,可以将状态和状态变更事件分布到各个子模块中。

mapState辅助函数,将多个状态传入。
组件仍然保有局部状态

Getter

有时候我们需要从 store 中的 state 中派生出一些状态。

getters接受state作为第一个参数。

const store = createStore({
    state:{
        todos:[
            {id:1,text:'...',done:true},
            {id:2,text:'...',done:false}
        ]
    },

    getters:{
        doneTodos(state){
            return state.todos.filter(to => todo.done);
        }
    }
})

getters会暴露store.getters对象,可以访问

注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的。

也可以通过getter返回一个函数,来实现给getter传参,在对store里的数组进行查询

注意,getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

mutation 必须是同步函数

为了在调试时,知道状态是可追踪的。

Action

  • action提交的是mutation,而不是直接变更状态
  • action可以包含任意异步操作
//注册一个简单的action
const store = createStore({
    state:{
        count:0
    },
    mutations:{
        increment(state) {
            state.count++;
        }
    },
    actions:{
        increment(context){
            context.commit('increment');
        }
    }
})

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

这里为什么用的是context???? 而不是store实例本身呢?

action通常是异步的,那么如何知道action什么时候结束?如何组合多个action,来处理更加复杂的异步流程???

store.dispatch可以处理被触发的action的处理函数返回的Promise,并且store.dispatch仍旧返回promise

const store = createStore({
    state:{},
    mutations:{},
    actions:{
        actionA({commit}){
            return new Promise((resolve,reject) => {
                setTimeout(() => {
                    commit('someMutation')
                    resolve()
                },1000)
            })
        }
    }
})


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

}),

//在另一个action中也阔以
actions:{
    actionB({dispatch,commi}){
        return dispatch('actionA').then(()=>{
            commit('someOtherMutation')
        })
    }
}
//最后利用async/await,进行如下组合action

actions:{
    async actionA({commit}){
        commit('gotData',await getData())
    },

    async actionB ({dispatch,commit}){
        await dispatch('actionA')
        commit('gotOtherData',await getOtherData())
    }
}

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

Module

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。应用十分复杂时,store对象就会变得臃肿。

解决上述问题,vuex允许我们将store分割成模块,每个模块拥有自己的state、mutation、action、getter甚至嵌套子模块,从上之下进行同样方式的分割

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

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

对于模块内部的mutation和getter,接收的第一个参数是模块的局部状态对象。

对于模块内部的action,局部状态通过context.state暴露出来,根节点状态则为contetx。rootState

项目结构

vuex并不限制你的代码结构,但有一些需要遵守的规则:

1、应用层级的状态应该集中到单个store对象中
2、提交mutation是更改状态的唯一方法,并且这个过程是同步的
3、异步逻辑都应该封装到action里面

组合式API

可以通过调用useStore函数,来在setup钩子函数中访问store,这与组件中使用选项式API访问this.$store是等效的

import {useStore} from 'vuex'

export default {
    setup(){
        const store = useStore()

        return {
            //在computed函数中访问state
            count:computed(()=> store.state.count),

            double:computed(() => store.getters.double),

            increment:() => store.commit('increment');
            asyncIncrement:() => store.dispatch('asyncIncrement')
        }
    }
}

你可能感兴趣的:(vue.js,前端,javascript)