美文网首页
Vuex(状态管理模式)

Vuex(状态管理模式)

作者: 南崽 | 来源:发表于2020-03-26 20:11 被阅读0次

    Vuex 是什么?

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

    使用

    在 Vue 的单页面应用中使用,需要使用Vue.use(Vuex)调用插件,将其注入到Vue根实例中。

    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    // 各组件相互共享数据的插件
    
    export default new Vuex.Store({
      // 数据存放地方
      state: {
    },
      // 方法存放地方
      mutations: {
    },
      // 反复存放地方(可以执行ajax)
      actions: {
      },
      // 模块
      modules: {
      }
    })
    

    核心

    • State,Getter,Mutation,Action,Module,

    Vuex 主要有四部分:

    • state:包含了store中存储的各个状态。
    • getter: 类似于 Vue 中的计算属性,根据其他 getter 或 state 计算返回值。
    • mutation: 一组方法,是改变store中状态的执行者,只能是同步操作。
    • action: 一组方法,其中可以包含异步操作。

    State

    Vuex 使用 state 来存储应用中需要共享的状态。为了能让 Vue 组件在 state更改后也随着更改,需要基于state 创建计算属性。

    // 创建一个 Counter 组件
    const Counter = {
      template: `<div>{{ count }}</div>`,
      computed: {
        count () {
          return this.$store.state.count  // count 为某个状态
        }
      }
    }
    

    Getter

    类似于 Vue 中的 计算属性(可以认为是 store 的计算属性),getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

    Getter 方法接受 state 作为其第一个参数:

    const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
        ]
      },
      getters: {
        doneTodos: state => {
          return state.todos.filter(todo => todo.done)
        }
      }
    })
    

    通过属性访问

    Getter 会暴露为 store.getters 对象,可以以属性的形式访问这些值:

    store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
    

    Getter 方法也接受 state和其他getters作为前两个参数。

    getters: {
      // ...
      doneTodosCount: (state, getters) => {
        return getters.doneTodos.length
      }
    }
    
    store.getters.doneTodosCount // -> 1
    

    我们可以很容易地在任何组件中使用它:

    computed: {
      doneTodosCount () {
        return this.$store.getters.doneTodosCount
      }
    }
    

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

    通过方法访问

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

    getters: {
      // ...
      getTodoById: (state) => (id) => {
        return state.todos.find(todo => todo.id === id)
      }
    }
    
    store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
    

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

    Mutation

    更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。也就是说,前面两个都是状态值本身,mutations才是改变状态的执行者。

    注意:mutations只能是同步地更改状态。

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

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

    调用 store.commit 方法:

    store.commit('increment')
    

    提交载荷(Payload)

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

    其中,第一个参数是state,后面的参数是向 store.commit 传入的额外的参数,即 mutation 的 载荷(payload)

    store.commit方法的第一个参数是要发起的mutation类型名称,后面的参数均当做额外数据传入mutation定义的方法中。

    规范的发起mutation的方式如下:

    // 以载荷形式
    store.commit('increment',{
      amount: 10   //这是额外的参数
    })
    
    // 或者使用对象风格的提交方式
    store.commit({
      type: 'increment',
      amount: 10   //这是额外的参数
    })
    

    额外的参数会封装进一个对象,作为第二个参数传入mutation定义的方法中。

    mutations: {
      increment (state, payload) {
        state.count += payload.amount
      }
    }
    

    Action

    想要异步地更改状态,就需要使用 action。action并不直接改变state,而是发起mutation。

    注册一个简单的 action:

    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 和 context.getters 来获取 state 和 getters。

    actions: {
      increment ({ commit }) {
        commit('increment')
      }
    }
    

    在action内部执行异步操作:

    actions: {
      incrementAsync ({ commit }) {
        setTimeout(() => {
          commit('increment')
        }, 1000)
      }
    }
    

    发起action的方法形式和发起mutation一样,只是换了个名字dispatch。

    // 以对象形式分发Action
    store.dispatch({
      type: 'incrementAsync',
      amount: 10
    })
    

    Actions 支持同样的载荷方式和对象方式进行分发

    Action处理异步的正确使用方式

    想要使用action处理异步工作很简单,只需要将异步操作放到action中执行要想在异步操作完成后继续进行相应的流程操作,有两种方式:

    1. store.dispatch返回相应action的执行结果,而action的处理函数返回的就是Promise,所以store.dispatch仍然返回一个Promise。

      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(() => {
            commit('someOtherMutation')
          })
        }
      }
      
    2. 利用async/await 进行组合action。代码更加简洁。

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

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

    Action与Mutation的区别

    Action 类似于 mutation,不同在于:

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作,而Mutation只能且必须是同步操作。

    Module

    • 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

    • 这时我们可以将 store 分割为模块(module),每个模块拥有自己的 stategettersmutationsactions 、甚至是嵌套子模块——从上至下进行同样方式的分割。

    代码示例:

    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 的状态
    

    相关文章

      网友评论

          本文标题:Vuex(状态管理模式)

          本文链接:https://www.haomeiwen.com/subject/pwqhuhtx.html