Vuex快速入门

2023-01-19  本文已影响0人  茜Akane

文档在这里: Vuex (vuejs.org)

1. Vuex 是什么?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
状态管理模式
让我们从一个简单的 Vue 计数应用开始:

new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  // view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

这个状态自管理应用包含以下几个部分:

以下是一个表示“单向数据流”理念的简单示意:

image.png
然而当多个组件共享状态(也就是数据)的时候,数据变动的来源变得不明显,逻辑变得繁琐不清晰。那么 vuex 就是将组件的共享状态抽取出来,以一个全局单例模式来管理的,专门为 Vue.js 设计的状态管理库,它利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
vuex
通俗地来讲,就是当页面应用过多且复杂,这个时候就适合用 vuex 在组件外部管理状态。

2. 安装

直接下载

npm install vuex --save
// npm 或 yarn
yarn add vuex

// 在一个模块化的打包系统中,必须显式地通过 Vue.use() 来安装 Vuex
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

CDN 引用
当使用全局 script 标签引用 Vuex 时,不需要以上安装过程。

<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>

3. State

创建一个 store,创建过程直截了当——仅需要提供一个初始 state 对象和一些 mutation:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

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

mapState函数
mapState 函数返回的是一个对象。它可以将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。

image.png
其中 ... 叫做 对象扩展运算符,可以将 mapState 返回的对象展开在所在位置上。

4. Getters

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getter 接受 state 作为其第一个参数,如果需要的话也可以接受其他 getter 作为第二个参数。

image.png
实例中的 fullName() 函数可以换成 ...Vuex.mapGetters(['fullName'])

5. Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方。
在上面的两个例子之中已经使用到了 mutation 。
还可以向 mutation 传入额外的参数,当然也可以传递一个对象。

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

Mutation 需遵守 Vue 的响应规则

  1. 需要提前在 store 中初始化好所有所需属性。
  2. 当需要在对象上添加新属性时,你应该

Mutation 必须是同步函数
每一条 mutation 都会被记录,如果使用异步,在 devtools 上将会很难捕捉前一状态与后一状态的快照。(实质上任何在回调函数中进行的状态的改变都是不可追踪的)
在组件中提交 Mutation
可以在组件中使用 this.$store.commit('xxx') 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

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')`
    })
  }
}

6. Action

Action 类似于 mutation,不同在于:

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.statecontext.getters 来获取 state 和 getters。
使用es6可以简化代码为:

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

分发Action
Action 通过 store.dispatch 方法触发:

store.dispatch('increment')

我们可以在 action 内部执行异步操作,也支持同样的载荷方式和对象方式进行分发:

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

// 以载荷形式分发
store.dispatch('incrementAsync', {
  amount: 10
})

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

来看一个更加实际的购物车示例,涉及到调用异步 API 和分发多重 mutation:

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)
    )
  }
}

简单地来说,就相当于我让朋友帮我去买书,买成功了就跟这个管理员结账,如果不成功,就去找另一个来解决。那么这个 checkout 就相当于朋友。

7. Modules

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

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 的状态
上一篇下一篇

猜你喜欢

热点阅读