vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。试想一下,如果在一个项目开发中两个组件不存在父子关系,他们之间传参就会很麻烦,只有一两个这种需求还好说,假设这个场景很多,在一个项目开发中频繁的使用组件传参的方式来同步data中的值,一旦项目变得很庞大,管理和维护这些值将是相当棘手的工作。这时候就体现出来Vuex的作用了。

属性:

state: 核心,驱动应用的数据源,类似于vue2.x中的 data;
getter:加工state成员给外界,类似于vue2.x中的 compted;
mutations:用来改变state的数据;
actions:异步操作
modules:模块化状态管理

VueX的工作流程

Vuex官网给出的流程图

首先,Vue组件如果调用某个VueX的方法过程中需要向后端请求时或者说出现异步操作时,需要dispatch VueX中actions的方法,以保证数据的同步。可以说,action的存在就是为了让mutations中的方法能在异步操作中起作用。

如果没有异步操作,那么我们就可以直接在组件内提交状态中的Mutations中自己编写的方法来达成对state成员的操作。注意,1.3.3节中有提到,不建议在组件中直接对state中的成员进行操作,这是因为直接修改(例如:this.$store.state.name = 'hello')的话不能被VueDevtools所监控到。还有就是严格模式会报错,一般情况下其实直接改了的话也没啥问题,哈哈。

最后被修改后的state成员会被渲染到组件的原位置当中去,也就是他是响应式的。

state

基本用法

1、用mapState 辅助函数
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState 辅助函数帮助我们生成计算属性,让你少按几次键:

// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组。

computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

对象展开运算符
mapState 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。但是自从有了『对象展开运算符』,我们可以极大地简化写法:

computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}

2、不用mapState,直接使用,store一般会直接挂载在VUE实例上,可以直接调用

this.$store.state.count

     {{ $store.state.count }}

增删state中的成员

为了配合Vue的响应式数据,我们在Mutations的方法中,应当使用Vue提供的方法来进行操作。如果使用delete或者xx.xx = xx的形式去删或增,则Vue不能对数据进行实时响应。

Vue.set 为某个对象设置成员的值,若不存在则新增

例如对state对象中添加一个age成员

Vue.set(state,"age",15)

Vue.delete 删除成员
将刚刚添加的age成员删除

Vue.delete(state,'age')

getters

mapGetters 辅助函数

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

import { mapGetters } from 'vuex'

export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }
}

如果你想将一个 getter 属性另取一个名字,使用对象形式:

...mapGetters({
  // 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
  doneCount: 'doneTodosCount'
})

Mutations使用方法

一条重要的原则就是要记住 mutation 必须是同步函数。
你可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store,Vue.use(Vuex);)。

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`

      // `mapMutations` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
    })
  }
}

mutations方法都有默认的形参:
([state] [,payload])
state是当前VueX对象中的state
payload是该方法在被调用时传递参数使用的,他只能传一个参数,后面传的拿不到都是undefined,想传多个参数就用对象的方式传就行了。

this.$store.commit('edit', { age:15,sex:'男' })

或者这样写(对象风格的提交方式)

this.$store.commit({
    type: 'edit',
    payload: {
        age:15,
        sex:'男'
    }
})

Actions

Action 类似于 mutation,不同在于:

Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
让我们来注册一个简单的 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。

用法:
你在组件中使用 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` 也支持载荷:
      'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    })
  }
}

modules

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

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割;用法跟直接写在store中是一样的,他有个属性叫 命名空间namespaced ,主要用于具有更高的封装度和复用性的模块,如果设置 namespaced: true,用法稍有不同,

modules: {
  cart: {
    namespaced: true,
    state: {
      goods: "abcdEFG"
    },
    getters: {
      toUpperGoods: state => {
        return state.goods.toUpperCase();
      }
    },
    mutations: {
      setGoods(state, val) {
        state.goods = val;
      }
    },
    actions: {
      setTokenAsync({ commit }, payload) {
        setTimeout(() => {
          commit("setGoods", payload);
        }, 1000);
      }
    }
  }
}

其他页面可以这样调用

{{ $store.getters["cart/toUpperGoods"] }}

没设置namespaced: true的话

{{ $store.getters["toUpperGoods"] }}

mapState、mapGetters、mapMutations、mapActions简单介绍

mapState、mapGetters 用在computed;
...mapGetters(["toUpperTest"]),
...mapGetters("cart", ["toUpperGoods"]),

mapMutations、mapActions 用在 methods
...mapMutations(['addAge']),
...mapActions("cart", ["toUpperGoods"]),

  methods: {
    ...mapActions("cart", ["setTokenAsync"]),
    changeName() {
      this.$store.dispatch("cart/setTokenAsync", "Jason");
    }
  }

参考:
Vue源码解读一:Vue数据响应式原理
VueX(Vue状态管理模式)
Getter | Vuex
vue中使用vuex(超详细)
vuex:弄懂mapState、mapGetters、mapMutations、mapActions

你可能感兴趣的:(vuex)