2

最近接触的项目比较常用vuex,因为之前基本不涉及vuex的使用,这里做一下记录。
首先表达一下看法:vuex是主要是用到存放一些全局的变量,可以看成是全局式的响应变量,便于统一管理,所以比较适合存取数据字典。

Vuex的核心

State

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

getter

类似于 Vue 中的计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getter 方法接受state作为其第一个参数:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    // 默认前两个参数
    doneTodos: (state, getters) => {
      return state.todos.filter(todo => todo.done)
    }
  }
})

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

store.getters.doneTodos

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

mutation

一组方法,是改变store中状态的执行者,只能是同步操作

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。也就是说,前面两个都是状态值本身,mutations才是改变状态的执行者。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和 一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

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

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

// 以载荷形式
store.commit('increment',{
  amount: 10   //这是额外的参数
})

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

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

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

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

Action

一组方法,含有异步操作的时候调用
想要异步地更改状态,就需要使用actionaction并不直接改变state,而是发起mutation
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用context.commit提交一个 mutation,或者通过context.statecontext.getters来获取 state 和 getters。

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

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

各个模块与 Vue 组件结合

stategetter结合进组件需要使用计算属性

computed: {
    count () {
      return this.$store.state.count 
      // 或者 return this.$store.getter.count
    }
  }

mutationaction结合进组件需要在methods中调用this.$store.commit()或者this.$store.commit():

methods: {
    changeDate () {
        this.$store.commit('change');
    },
    changeDateAsync () {
        this.$store.commit('changeAsync');
    }
}

为了简便起见,Vuex 提供了四个辅助函数方法用来方便的将这些功能结合进组件。

  1. mapState
  2. mapGetters
  3. mapMutations
  4. mapActions

示例代码:

import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
    // ...
    computed: {
      localComputed () { /* ... */ },
        // 使用对象展开运算符将此对象混入外部对象中
      ...mapState({
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        count(state) {
          return state.count + this.localCount
        }
      }),
      ...mapGetters({
        getterCount(state, getters) {
          return state.count + this.localCount
        }
      })
    }
    methods: {
      ...mapMutations({
          // 如果想将一个属性另取一个名字,使用以下形式。注意这是写在对象中
           add: 'increment' // 将 `this.add()` 映射为`this.$store.commit('increment')`
        }),
      ...mapActions({
          add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
        })
    }
}

如果结合进组件之后不想改变名字,可以直接使用数组的方式。

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

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

吴静仪
26 声望2 粉丝

无我


引用和评论

0 条评论