Vue状态管理-Vuex

前言

参考:Vuex官网vue.js官网

Vuex是什么

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

这是官网对Vuex的定义,我们可以看出:

  • Vuex 是专门为 Vue.js 设计的状态管理库
  • 采用集中管理应用中多个组件之间需要共享的数据,解决了复杂组件通信,实现数据共享
  • 集中管理的数据以一种可预测的方式变化

Vuex应用场景

组件化是Vue.js核心之一,组件化则可以给我们带来更快的开发效率和更好的维护性,在Vue项目中,每个页面都可以看成是一个组件,大多数场景下的组件都并不是独立存在的,而是相互协作共同构成了一个复杂的业务功能,这就导致了组件状态间错综复杂的关系,管理好这些状态也变的尤为重要。通过官网的定义,我们知道Vuex设计的初衷就是解决这个问题的,那是不是所有Vue.js的应用都可以使用Vuex呢?

Vuex 可以帮助管理共享状态,但也附带了更多的概念和框架,如果一个应用足够简单,只有几个简单的页面,使用 Vuex 无疑是繁琐冗余的,会无形中增加开发工作量,从而影响开发效率。但是当我们构建一个中大型单页应用,多个组件依赖同一状态,多个组件需要通过内部的方法去更改同一状态时,Vuex便是最好的选择。

Vuex核心概念

在这里插入图片描述
从官网的这张图可以看出,Vuex的核心是state、actions、mutations。

state
state是应用组件共享的状态,存储在 Vuex 的核心仓库store中,形成单一状态树,store内存储的状态都是响应式的,当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地更新。

new Vuex.Store({
  state: {
    name: 'zhangsan',
    sex: '男',
    age:10
  }
})

在组件中获取Vuex中的state有三种方式

  • 最简单的方式是通过计算属性获取
// 创建一个 Counter 组件
const Counter = {
   template: `<div>{{ count }}</div>`,
   computed: {
      count () {
         return store.state.count
      }
   }
}

  • 通过从根组件注入的store
// 根组件,把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
const app = new Vue({
  el: '#app',
  store,
  components: { Counter },
  template: `
    <div class="app">
      <counter></counter>
    </div>
  `
})

//子组件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}
  • 通过mapState辅助函数,mapState 函数返回的是一个对象
import { mapState } from 'vuex'
//1.基本用法
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: mapState({
      count: state => state.count,
      // 传字符串参数 'count' 等同于 `state => state.count`
      countAlias: 'count',
  })
}

//2.组件中的计算属性名和store中的state名一致时,可以给 mapState 传一个字符串数组
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: mapState(['count'])
}

//3.使用对象展开运算符
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
     ...mapState(['count'])
  }
}

mutations

  1. 提交 mutation是更改 Vuex 的 store 中的状态的唯一方法
  2. mutation类似于事件,每个 mutation 都有字符串事件类型 (type) 和 回调函数 (handler)
  3. 每个mutation回调函数第一个参数必须是state(状态),第二个非必须参数payload(字符串或对象)
  4. 每个mutation必须是同步函数

提交mutation方式

//1.提交载荷
mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10) //载荷是普通值

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit('increment', { amount: 10 })//载荷是对象

//2.对象风格提交
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
store.commit({ type: 'increment', amount: 10 })

actions

  1. action提交mutation,不能直接更改store中的状态
  2. 每个 action都有字符串事件类型 (type) 和 回调函数 (handler)
  3. action可以是同步函数,也可以是异步函数

通过store.dispatch()分发Actions

//1.不带参数分发
actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
store.dispatch('increment')

//2.带参数方式分发
actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}
store.dispatch('incrementAsync', { amount: 10 }) //以载荷形式分发
store.dispatch({ type: 'incrementAsync', amount: 10 }) //以对象形式分发

在组建中分发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')`
    })
  }
}

除了以上三个主要核心概念外,还有getters和modules。
Getters

  • getters的作用类似于vue.js里的计算属性,返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
  • getter接收state 作为其第一个参数,接收其他getter作为第二个参数。

访问getter的方式

//1.通过属性访问(getter会暴露为 store.getters 对象)
getters: {
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length
  }
}
store.getters.doneTodosCount // -> 1

//2.通过方法访问(让 getter 返回一个函数,来实现给 getter 传参)
getters: {
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2)

//3.通过mapGetters辅助函数
import { mapGetters } from 'vuex'

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

Modules

  • 以免store过于庞大复杂,Vuex允许我们从上至下将 store 分割成模块,每个模块拥有自己的
    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 的状态

  • 模块的局部状态
    模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象
const moduleA = {
  state: () => ({
    count: 0
  }),
  mutations: {
    increment (state) {
      // 这里的 `state` 对象是模块的局部状态
      state.count++
    }
  },

  getters: {
    doubleCount (state) {
      return state.count * 2
    }
  }
}

对于模块内部的action,context.state为局部状态,context.rootState为根节点状态

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

对于模块内部的getter,第三个参数是根节点状态

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值