banner
banner
banner
NEWS LETTER

VUE3-VUEX(状态管理库)

Scroll down

在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

  • 点击查看安装步骤
  • 每一个 Vuex应用的核心就是 store(仓库)
  • 修改store值的唯一方法就是通过mutation来修改
  • actions不能直接修改state需要通过mutations提交修改state,actions可以进行异步操作

状态管理模式

  • 状态:驱动应用的数据源 — data
  • 视图:以声明方式将状态映射到视图 — template
  • 操作: 响应在视图上的用户输入导致的状态变化 — methods
    vuex

不使用单向数据流的原因:

  • 使用场景:多个组件共享状态 – 会依赖同一状态和变更同一状态(单向数据流的简洁性会被破坏)

Vuex 和单纯的全局对象的不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。

创建一个简单的store(vue2版)

  • 创建文件:src/store/index.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // 引入Vue核心库
    import Vue from 'vue'
    // 引入Vuex
    import Vuex from 'vuex'
    // 应用Vuex插件
    Vue.use(Vuex)
    // 准备actions对象——响应组件中用户的动作
    const actions = {
    jiaWait(context,value){
    setTimeout(()=>{
    context.commit('increment',value)
    },500)
    }
    }
    // 准备mutations对象——修改state中的数据
    const mutations = {
    increment(state,value){
    state.count += value
    },
    }
    //准备state对象——保存具体的数据
    const state = { count: 0 }
    //准备getters——用于将state中的数据进行加工
    const getters = {
    bigSum(state){
    return state.count*10
    }
    }
    //创建并暴露store
    export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
    })
  • main.js中引入store,并将store添加到new Vue中

基本使用

  • 初始化数据、配置actions、配置mutations,操作文件store.js
  • 读取vuex中的数据:页面通过store.state来获取状态对象,组件通过this.$store老访问store实例
  • 修改vuex中的数据:通过this.$store.dispatch('action中的方法名',数据)this.$store.commit('mutations中的方法名',数据)
  • 注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

state — 单一状态树

  • 组件中获得 Vuex 状态 – 在computed中返回某个state

Getter — store 的计算属性

  1. 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
  2. 组件中读取数据:$store.getters.count

Mutation — 更改state的唯一方法 且必须是同步函数

  • 提交的两种方式(传入额外的参数)
    • 载荷(Payload)
      • store.commit(‘mutation的方法名’, {额外参数: n})
    • 对象风格
      • store.commit({type: ‘mutation的方法名’,额外参数: n})

Action — 包含异步操作且提交的是Mutation

1
2
3
4
actions: { increment({commit}) {
commit('mutations的方法名')
}
}
  • 载荷形式分发
    • store.dispatch(‘actions的方法名’, {额外参数: n})
  • 以对象形式分发
    • store.commit({type: ‘actions的方法名’, 额外参数: n})

组合Action

  • store.dispatch可以处理触发的action的处理函数返回Promise
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    actions: {
    actionA({ commit }) {
    return new Promise((resolve,reject) => {
    setTimeout(() => {
    commit('someMutation')
    resolve()
    },1000)
    })
    }
    }
    store.dispatch('actionA').then(()=>{})
    // 设 gotData(),getOtherData() 返回的是Promise
    actions: {
    async actionA({commit}) {
    commit('gotData', await getData())
    },
    async actionB ({ dispatch, commit}) {
    await dispatch('actionA')
    commit('getOtherData',await getOtherData)
    }
    }

map方法的使用

mapState方法:映射state中的数据为计算属性

  • 使用:在computed中将state的数据拿出来
    • 对象写法:…mapState({再定义的变量名:’变量名’})
    • 数组写法:…mapState([‘变量名’])

mapGetters方法:映射getters中的数据为计算属性

  • 使用:在computed中将getters的方法拿出来
    • 对象写法:…mapGetters({再定义的方法名:’方法名’})
    • 数组写法:…mapGetters([‘方法名’])

mapActions方法:

  • 生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数
  • 使用:在computed中将actions的方法拿出来
    • 对象写法:…mapActions({再定义的方法名:’方法名’})
    • 数组写法:…mapActions([‘方法名’])

mapMutations方法:

  • 生成与mutations对话的方法,即:包含$store.commit(xxx)的函数
  • 使用:在computed中将mutations的方法拿出来
    • 对象写法:…mapMutations({再定义的方法名:’方法名’})
    • 数组写法:…mapMutations([‘方法名’])
  • 注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。

Module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const moduleA = {
state: () => ({...}),
mutations: {...}, // 局部模块的state
actions: {...}, // 局部模块的context.state和根节点状态context.rootState
getters: {...},// 局部模块的state,根节点状态rootState会作为第三个参数
}
const moduleB = {
state: () => ({...}),
mutations: {...},
actions: {...},
getters: {...}
}
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

模块化+命名空间

目的:让代码更好维护,让多种数据分类更加明确。

修改store.js

1
2
3
4
5
6
7
modules: {
模块1: {
namespaced: true, // 开启命名空间,getters、action、mutation有影响
state: () => ({...}),
getters:{...}
}
}

开启命名空间后,组件中读取state数据:

  • 方式一:自己直接读取
  • this.$store.state.xxx
  • 方式二:借助mapState读取:
  • …mapState(‘模块名’,[‘state的属性’])

开启命名空间后,组件中读取getters数据:

  • 方式一:自己直接读取
  • this.$store.getters[‘模块名/getters的方法’]
  • 方式二:借助mapGetters读取:
  • …mapGetters(‘模块名’,[‘getters的方法’])

开启命名空间后,组件中调用dispatch

  • 方式一:自己直接dispatch
    • this.$store.dispatch(‘模块名/actions的方法’,传参)
  • 方式二:借助mapActions:
    • …mapActions(‘模块名’,{定义的别名:’actions的方法’,定义的别名:’actions的方法’})

开启命名空间后,组件中调用commit

  • 方式一:自己直接commit
    • this.$store.commit(‘模块名/mutations的方法’,传参)
  • 方式二:借助mapMutations:
    • …mapMutations(‘模块名’,{别名:’mutations的方法’,别名:’mutations的方法’}),

在带命名空间的模块内访问全局内容

  • 使用全局 state 和 getter,rootState 和 rootGetters 会作为第三和第四参数传入 getter,也会通过 context 对象的属性传入 action。
  • 全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。

在带命名空间的模块注册全局 action

  • 在命名空间的actions方法中给要注册为全局的方法添加root: truehandler (namespacedContext, payload) { ... }

模块动态注册 store.registerModule

1
2
3
4
5
6
import { createStore } from 'vuex'
const store = createStore({})
store.registerModule('myModule',{}) // 注册模块
store.registerModule(['nested','myModule'],{}) // 注册嵌套模块 /nested/myModule
store.unregisterModule(modulename) // 卸载动态模块,静态不行
store.hasModule(moduleName) // 检查是否被注册到store,注意嵌套模块要以数组形式传递
  • 保留 state
    • store.registerModule(‘a’,module, {preserveState: true})

vue3的vuex

  • 与vue2比,引入时需要从vuex导入createStore
    1
    2
    3
    4
    5
    6
    7
    import { createStore } from 'vuex'
    export default createStore({
    state: {},
    mutations: {},
    actions: {},
    modules: {}
    })
  • 使用,在setup中:const store = useStore();然后直接store.xxx即可

组合式API

  • 调用useStore,在setup中访问store == this.$store
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import { useStore } from 'vuex'
    export default {
    setup () {
    const store = useStore()
    return {
    // 在 computed 函数中访问 state
    count: computed(() => store.state.count),
    // 在 computed 函数中访问 getter
    double: computed(() => store.getters.double)
    // 使用 mutation
    increment: () => store.commit('increment'),
    // 使用 action
    asyncIncrement: () => store.dispatch('asyncIncrement')
    }
    }
    }

插件

1
2
3
4
5
6
7
8
9
10
const myPlugin = (store) => {
// 当store 初始化调用
store.subscribe((mutation,state) => {
// 每次mutation 之后调用
// mutation的格式为{type, payload}
})
}
const store = createStore({
plugin: [myPlugin]
})

严格模式

  • 在store中strict:process.env.NODE_ENV !== ‘production’ // 发布环境不能为true

表单处理

方法一:v-model 用v-bind绑定value和v-on去监听实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<input :value="message" @input="updateMessage" />
computed: {
...mapState({
message: state => state.message
})
},
methods: {
updateMessage (e) {
this.$store.commit('updateMessage',e.detail.value)
}
}
const store = createStore ({
mutations: {
updateMessage (state,message) {
store.message = message
}
}
})

方法二: 用getter和setter的双向绑定计算属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<input v-model="message" />
computed: {
message: {
get() {
return this.$store.state.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
const store = createStore ({
mutations: {
updateMessage (state,message) {
store.message = message
}
}
})

支持ts

在vuex.d.ts中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// vuex.d.ts
import { Store } from 'vuex'

declare module '@vue/runtime-core' {
// 声明自己的 store state
interface State {
count: number
}

// 为 `this.$store` 提供类型声明
interface ComponentCustomProperties {
$store: Store<State>
}
}

useState 组合式函数类型声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// store.ts
import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'

export interface State {
count: number
}

export const key: InjectionKey<Store<State>> = Symbol()

export const store = createStore<State>({
state: {
count: 0
}
})

// 定义自己的 `useStore` 组合式函数
export function useStore () {
return baseUseStore(key)
}
其他文章
cover
VUE3-常用的修饰符
  • 24/11/01
  • 14:39
  • VUE
cover
VUE3-路由
  • 24/11/01
  • 14:39
  • VUE
目录导航 置顶
  1. 1. 状态管理模式
  2. 2. 不使用单向数据流的原因:
  3. 3. Vuex 和单纯的全局对象的不同:
  4. 4. 创建一个简单的store(vue2版)
  5. 5. 基本使用
    1. 5.1. state — 单一状态树
    2. 5.2. Getter — store 的计算属性
    3. 5.3. Mutation — 更改state的唯一方法 且必须是同步函数
    4. 5.4. Action — 包含异步操作且提交的是Mutation
    5. 5.5. 组合Action
  6. 6. map方法的使用
    1. 6.1. mapState方法:映射state中的数据为计算属性
    2. 6.2. mapGetters方法:映射getters中的数据为计算属性
    3. 6.3. mapActions方法:
    4. 6.4. mapMutations方法:
  7. 7. Module
  8. 8. 模块化+命名空间
    1. 8.1. 目的:让代码更好维护,让多种数据分类更加明确。
    2. 8.2. 修改store.js
    3. 8.3. 开启命名空间后,组件中读取state数据:
    4. 8.4. 开启命名空间后,组件中读取getters数据:
    5. 8.5. 开启命名空间后,组件中调用dispatch
    6. 8.6. 开启命名空间后,组件中调用commit
    7. 8.7. 在带命名空间的模块内访问全局内容
    8. 8.8. 在带命名空间的模块注册全局 action
    9. 8.9. 模块动态注册 store.registerModule
  9. 9. vue3的vuex
  10. 10. 组合式API
  11. 11. 插件
    1. 11.1. 严格模式
  12. 12. 表单处理
    1. 12.1. 方法一:v-model 用v-bind绑定value和v-on去监听实现
    2. 12.2. 方法二: 用getter和setter的双向绑定计算属性
  13. 13. 支持ts
    1. 13.1. 在vuex.d.ts中添加
    2. 13.2. useState 组合式函数类型声明
请输入关键词进行搜索