Vuex - 组件全局状态(数据)管理机制

总结:
组件全局状态(数据)管理机制Vuex的安装、导入及使用
四大核心概念使用
1. State 存储数据
(1) this.$store.state.全局数据名称
(2) import { mapState } from 'vuex' —— computed: { ...mapState(['count']) }
2. Mutation 修改数据(同步)
(1) this.$store.commit('addN', 3) // 触发时,携带参数
(2) import { mapMutations } from 'vuex' —— methods: { ...mapMutations(['add','addN']) }
3. Action 处理异步逻辑,并触发 Mutation 以间接更新 State
(1) this.$store.dispatch('addNAsync', 3) // 携带参数
(2) import { mapActions } from 'vuex' —— methods: { ...mapAction(['addAsync','addNAsync']) }
4. Getter 提供数据加工
(1) this.$store.getters.名称
(2) import { mapGetters } from 'vuex' —— computed: { ...mapGetters(['showNum']) }

概述

  1. 组件之间共享数据的方式
    父向子:porps自定义属性
    子向父:自定义事件$.emitv-on/@
    兄弟组件之间:EventBus$.emit$.on

    这三种的方式,只适合在小范围内来进行数据的共享
    如果需要频繁的,或者大范围的来实现数据的共享,这三种方案就有些力不从心

  2. Vuex
    Vuex实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享
    vuex
    Vuex就相当于在这些组件旁边定义了一个共享的数据状态对象Store

  3. 使用Vuex统一管理状态的好处

    • 能够在vuex中集中管理共享的数据,易于开发和后期维护
    • 能够高效地实现组件之间的数据共享,提高开发效率
    • 存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步
  4. 什么样的数据适合存储到Vuex中
    一般情况下,只有组件之间共享的数据才有必要存储到vuex中;对于组件中的私有数据,依旧存储在组件自身的data中即可。

基本使用

  1. 安装vuex依赖包:npm i vuex -S
  2. 导入vuex包
    import Vuex from 'vuex'
    Vue.use(Vuex)
  3. 创建store对象
    1
    2
    3
    4
    const store = new Vuex.Store({
    // state中存放的就是全局共享的数据
    state: { count: 0 }
    })
  4. 将store对象挂载到vue实例中
    1
    2
    3
    4
    5
    6
    7
    8
    new Vue({
    el: '#app',
    render: h => h(app),
    router,
    // 将创建的共享数据对象,挂载到Vue实例中
    // 所有的组件,就可以直接从store中获取全局的数据了
    store
    })

创建vue项目时,如果添加了vuex的配置,会自动帮我们配置好这些

核心概念

Vuex中主要的核心概念如下:

  • State
  • Mutation
  • Action
  • Getter

总结来说,State 存储数据Getter 提供数据加工Mutation 修改数据(同步),而 Action 处理异步逻辑并触发 Mutation 以间接更新 State。这四者共同构成了 Vuex 的核心机制,帮助开发者更好地管理和维护应用的状态。

State

State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储。

  • 组件访问State中数据方式一直接访问
    this.$store.state.全局数据名称,如this.$store.state.count

  • 组件访问State中数据的方式二使用mapState辅助函数

    1. 从vuex中按需导入mapState函数
      import { mapState } from 'vuex'
    2. 通过mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
      1
      2
      3
      computed: {
      ...mapState(['count'])
      }
      或者使用对象展开语法进行更细致的映射:
      1
      2
      3
      4
      5
      computed: {
      ...mapState({
      localCount: state => state.count
      })
      }
  • 使用方式建议

    • 只需要访问一两个State属性,且不频繁使用 —— 直接访问
    • 访问多个State属性,或者需要对State数据进行一些转换处理 —— mapState辅助函数

      更加清晰和高效,使代码更模块化,易于阅读和维护。

    • 项目使用了TS —— mapState辅助函数

      mapState配合类型注解可以提供更好的类型安全性。

    总的来说,选择哪种方式取决于具体场景和个人偏好,但通常推荐使用mapState,因为它可以让你的代码更加整洁、易于维护,并且在处理复杂逻辑时更为灵活

Mutation

在组件中,虽然可以this.$store.state.count = 1直接修改全局的数据,且不报错,
但是在Vuex中,它不允许组件直接去修改Store的数据,而是推荐使用Mutation

Mutation用于变更Store中的数据。
通过这种方式虽然操作稍微繁琐一些,但是可以集中监控所有数据的变化

通过this.$store.state.count = 1修改数据,如果想看一下是谁修改的,需要挨个组件去翻,不利于后期维护。
通过Mutation里面的函数修改数据,如果发现数据修改有问题,可以直接找对应的Mutation

定义Mutations

1
2
3
4
5
6
7
8
9
10
const store = new Vuex.Store({
state:{
count: 0
},
mutations: {
add(state) {
state.count++ // 变更状态
}
}
})
  • 传递参数
1
2
3
4
5
6
7
8
const store = new Vuex.Store({
// ...
mutations: {
addN(state, step) {
state.count += step // 变更状态
}
}
})

触发方式一

1
2
3
4
5
6
7
8
methods: {
handlel() {
// 注意这里是**小写**store!!!
// commit的作用,就是调用某个mutation函数
this.$store.commit('add')
this.$store.commit('addN', 3) // 触发时,携带参数
}
}

触发方式二

  1. 从Vuex中按需导入 mapMutations 函数:
    import { mapMutations } from 'vuex'

    注意是小写vuex

  2. 通过mapMutations函数,将需要的mutations函数,映射为当前组件的methods方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    methods: {
    ...mapMutations(['add','addN'])
    }

    // 可以直接调用
    <button @click="add">count +1</button>
    <button @click="addN(3)">count +3</button> // 携带参数
    // 也可以在方法中调用 -- 推荐
    methods: {
    ...mapMutations(['add','addN']),
    btnHandle1(){
    this.add()
    },
    btnHandle2(){
    this.addN(3) // 携带参数
    }
    }

Action

在Mutations函数中,不能写异步的代码(setTimeout、setIterval等),虽然页面效果没有问题,但是数据没有传到state,会导致在devtools提交更新后,页面的数据又恢复原来的了

Action 用于处理异步任务
但是在Action中,还是要通过触发Mutation的方式间接变更数据

定义Action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const store = new Vuex.store({
// ...
mutations: {
add(state) {
state.count++
}
},
actions: {
// 只有mutations函数中,才有权利修改state中的数据
// 在actions中,必须通过context.commit()触发某个mutation才行
addAsync(context){
setTimeout(()=>{
context.commit('add')
},2000)
}
}
})
  • 传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const store = new Vuex.store({
// ...
mutations: {
addN(state, step) {
state.count += step
}
},
actions: {
addNAsync(context,step){
setTimeout(()=>{
context.commit('addN',step)
},2000)
}
}
})

触发Action - 方式一

1
2
3
4
5
6
7
8
9
methods: {
add() {
// 这里的dispatch函数,站门用来触发action
this.$store.dispatch('addAsync')
},
addN() {
this.$store.dispatch('addNAsync', 3) // 携带参数
}
}

触发Action - 方式二

和Mutations一样

  1. 从Vuex中按需导入 mapActions 函数:
    import { mapActions } from 'vuex'

    注意是小写的vuex

  2. 通过mapActions函数,将需要的actions函数,映射为当前组件的methods方法
    1
    2
    3
    methods: {
    ...mapActions(['addAsync','addNAsync'])
    }

Getter

Getter用于对Store中的数据进行加工处理形成新的数据。起到一个包装数据的作用,类似计算属性computed

  • 定义Getter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const store = new Vuex.store({
    state: {
    count: 0
    },
    getters: {
    showNum: state=>{
    return '当前最新的数量是【' + state.count +'】'
    }
    }
    })

Getters的使用同样和State一致

  • 使用Getter方式一
    this.$store.getters.名称如:this.$store.getters.showNum

  • 使用Getter方式二 —— mapGetters

    1. 从vuex中按需导入mapGetters函数
      import { mapGetters } from 'vuex'
    2. 通过mapGetters函数,将当前组件需要的getters,映射为当前组件的computed计算属性
      1
      2
      3
      computed: {
      ...mapGetters(['showNum'])
      }

关于核心概念的使用方式

就像state中说到的那样:

  • 使用不频繁 —— 直接访问
  • 访问多次,或者需要进行转换处理 —— mapXXX辅助函数

    更加清晰和高效,使代码更模块化,易于阅读和维护。

  • 项目使用了TS —— mapXXX辅助函数

    mapXXX辅助函数配合类型注解可以提供更好的类型安全性。

总的来说,选择哪种方式取决于具体场景和个人偏好,但通常推荐使用mapXXX辅助函数,因为它可以让你的代码更加整洁、易于维护,并且在处理复杂逻辑时更为灵活