vuex中五大核心以及插件plugins

Vuex是一个专为Vue.js应用设计的状态管理模式,它集中管理组件共享状态,确保状态变化的可预测性。文章详细介绍了Vuex的五大核心:state(状态)、mutations(提交状态变更)、actions(包含异步操作)、getters(计算属性)和modules(模块化)。此外,还提及了如何使用plugins(插件)实现状态的持久化。

什么是vuex?

在vuex的官方文档中表示
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
那什么是状态管理模式呢?
vue组件之间通讯使用的是单向数据流
但是当多个组件共享状态时,单向数据流的简洁性很容易被破坏。

  • 多个视图依赖于同一状态。
  • 来自不同视图的行为需要变更同一状态。
    对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!

通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。

这就是 Vuex 背后的基本思想

vuex的五大核心和使用方法

1. state

state 状态 也可以称为是vuex中的库 保存所有组件公用的数据

mapState 辅助函数

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

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

computed: mapState([

  'count'
])

或者使用对象展开运算符将此对象混入到外部对象中

computed: {
  localComputed () {  },

  ...mapState({
  })
}

2. mutations

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

//创建vuex实例
const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }
})

在使用时不能直接调用一个 mutation 处理函数。这个选项更像是事件注册:你需要以相应的 type 调用
store.commit 方法:

store.commit('mutations中函数名')

调用传参
你可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload)
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读

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

同时我们也可以以对象的形式提交
提交 mutation 的另一种方式是直接使用包含 type 属性的对象
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此处理函数保持不变

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

实际项目运行时的重中之重
Mutation 必须是同步函数 官网中给出的解释是为了让mutation的每一次修改都可以被追踪到也就是意味着 每次执行后都会通过监听将数据更新到state中,如果变为异步,不知道何时完成,state将无法被有效更新

最后在组件中使用:

在组件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。

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

3. actions

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

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

const store = createStore({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})

实践中,我们会经常用到参数解构来简化代码(特别是我们需要调用 commit 很多次的时候):

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

在组件中使用 Action

在组件中使用 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')`
    })
  }
}

最后 我们还可以用promise或者async与await来异步使用action和监控执行状态

4. getters

vuex中的计算属性
Getter 接受 state 作为其第一个参数也可以接受其他 getter 作为第二个参数

getters: {
  // ...
  doneTodosCount (state, getters) {
    return getters.doneTodos.length
  }
}

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

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

mapGetters 辅助函数
mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
如果你想将一个 getter 属性另取一个名字,使用对象形式:

import { mapGetters } from 'vuex'

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

5. modules

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

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 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,接收的第一个参数是模块的局部状态对象。对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。对于模块内部的 getter,根节点状态会作为第三个参数暴露出来.

const moduleA = {
  state: () => ({
    count: 0
  }),
  mutations: {
    increment (state) {
      // 这里的 `state` 对象是模块的局部状态
      state.count++
    }
  },

  getters: {
    sumWithRootCount (state, getters, rootState) {
      return state.count + rootState.count
    }
  }

  actions: {
    incrementIfOddOnRootSum ({ state, commit, rootState }) {
      if ((state.count + rootState.count) % 2 === 1) {
        commit('increment')
      }
    }
  }
}

命名空间
默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
在现阶段尚未使用过多模块 这里就不做详解了

最后提一个五大核心以外的 plugins 插件
我们通常在插件里安装vuex的持久化 来解决页面刷新会丢失数据这一现象
具体步骤:
1、安装

npm install vuex-persistedstate --save

2在store下的index.js中引入

import createPersistedState from "vuex-persistedstate";

3、在文件中最后面引入

plugins: [
    createPersistedState({
      // 存储方式:localStorage、sessionStorage、cookies
      storage: window.cookies,//存储到cookie
      // storage:window.sessionStorage 存储到sessionStorage
      // 如果不写默认存储到localStorage
      // 存储的 key 的key值
      key: "store",
      render(state) {
        // 要存储的数据:本项目采用es6扩展运算符的方式存储了state中所有的数据
        return { ...state };
        //需要存储其中的某些数据的话需要单独取出来
       // return {
        	//只储存state中的assessmentData
            //assessmentData: val.assessmentData
      }
    })
  ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值