(syntax)vuex
2022-10-20 10:31:20

vuex

写在前面

  • vuex 状态管理 也可以说是全局数据管理,就是把每个页面或者组件的data抽离处理挂载到store上,方便统一管理、组件之间的通信、多个状态变更

  • 五大块:store (仓库、容器) state(数据、状态)、getters(全局计算属性)、mutaions(同步变更 commit)、action(异步变更 mutations)、moudle(抽离成模块)

    • state(mapState) getters(mapGetters) mutations(mapMutations || commit )/mutation-type.js actions(mapAction || context || { commit } || dispath)
  • mapXxx([]/{}) 辅助函数:全局$store传递到组件的参数 获取多个的操作

  • mapXxx的使用位置 computed:{ mapState\mapGetters } methods:{ mapState\mapGetters }

  • store vs state vs mutations vs action vs getters :

    • store是一个仓库 {} 对象 挂载到全局$store
    • state是数据源也是全局的data
    • getters可以理解为全局的计算属性(有缓存) vs mutaions的区别是 (计算属性和方法的区别)
    • mutations和action可以理解为(全局的方法) 其中mutaions处理同步变更、action有两种功能处理异步变更、也可以处理多步mutations变更。其中 使用mutation的方法是commit()方法改变、 action是dispatch()触发

VuexAPI

1
2
npm i vuex --save-dev
yarn add vuex
  • state(状态):存放状态(驱动应用的数据源)
    • 定义:state:{}
    • 使用:
      • 全局:==this.$store.state.xxx==
      • 局部:==this.state.xxx== + mapState 获取多个状态
        • computed:mapState({}//[]) computed:( ...mapState({}//[])) {} 别名 [] 多值
  • getters 加工state成员给外界 计算属性 computer 计算属性
    • 定义:getter:{ 值(state){ }}
    • 使用:
      • 全局:==this.$store.getters.xxx==
      • 局部:==this.getters.xxx== + mapGetters
    • this.getter
  • mutations(变更) :state 成员操作 ==> Vuex [commit方法]提交更改 (更改 Vuex state 的唯一方法,同步操作)
    • 定义:mutations:{ [XXX](){} }
    • 使用:
      • 全局:==this.$store.commit(‘xxx’)==
      • 局部:==this.commit(‘xxx’)== + mapMutations
  • actions(动作) :状态变化 (异步操作) (异步操作处理方法,提交 mutation 来更改 state,而不是直接变更)
    • 定义
      • 处理muations: actions:{ xxx//xxx为mutaions方法({commit}){ commit('xxx') } }
      • 异步:incrementAsync({commit}){ setTimeout(()=>{},3000) }
    • 使用:
      • 全局:==this.$store.dispatch(‘xxx’)==
      • 局部:==this.dispatch(‘xxx’)== + ``mapActions`
  • 工程化
    • 模块划分:modules(模块) :模块化状态管理
    • 文件划分:五文件划分

Vuex 是一个专为 Vue.js 应用程序开发的状态管理(设计模式)模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。(把组件中的data(状态)提取为全局变量 让每一个组件都能访问到 VueX是全局的变量)

  • store 集中存储多个组件的状态(data)[整个应用所需的信息]
  • 各个组件获取store组件内存储的数据

单向数据流(State + Actions + View ) ==> 简单的store 模式 ==> 状态管理模式 (State + Actions +Mutations)

view :将 state映射到视图 ==> 单向数据流

页面data从组件中分离出来方便状态之间共享 通过commit方式进行数据的变更方便追踪数据流

store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更

State状态

vuex3(vue2)

  • 定义注册 main.js + store.js
    • export default new Vuex.Store({ state:{ xxx } }) 导出Vuex.Store
    • import(./store) + new Vue({ store }) 导入 + 注册Vue
  • 使用:任何地方
    • this.$store.state.xxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// main.js
import App from './App.vue'
import store from './store'

new Vue({
store, // 注册
render: function (h) { return h(App) }
}).$mount('#app')

// store.js
export default new Vuex.Store({
state: { // 状态 存储全局data数据 == data
count:100
}
})

// 调用
this.$store.state.count

vuex4(vue3)

  • import{createStore} + export default createStore({ state }) 导出createStore
  • import{createApp} + import(store) + createApp(app).use(store).mount(‘#app’) 导入 createApp(App).use()
1
2
3
4
5
6
7
8
9
10
11
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).use(router).mount('#app') // 注册

// store.js
import { createStore } from 'vuex'
export default createStore({
// state getters mutations actions modules :{ }
})

组件使用state的方法

  • state vs mapState({}) 组件获取state的方法

    • this.$store.state.count/state.count 获取单个state

    • mapState({}) 获取多个state mapState({ }) 获取多个状态的计算属性 函数返回一个对象 将他与局部计算属性混合使用

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

      • mapState 辅助函数帮助我们生成计算属性 映射 this.count 为 store.state.count 传递多个值到组件

mapState()两种写法 computed:mapState() vs computed:{ …mapState() } 参数[]或{}

  • computed:mapState({}//[])
    • 对象:computed:mapState({ num: (state) => state.count, })
    • 数组:computed: mapState(['num1','num2']) 计算属性的名称与 state 的子节点名称相同时,我们也可以给mapState传一个字符串数组
  • computed:{...mapState({}/[])}
    • 对象展开符:computed:{ ...mapState(['num1','num2'])} 更同一组件传递多个state
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
36
// store.js
import { createStore } from 'vuex'
export default creatStore({
state:{
firstCount:1000,
secondCount:2000,
secondCount:3000
}
})


<h1>xxx</h1>
// ? 单个组件获取多个state 通过mapState
// xxx.vue
import { mapState } from 'vuex'
export default{
computed:{
xxx(){
return xxx
}
},
computed:mapState(['firstCount','secondCount','secondCount'])
computed:mapState({
count:state => state.count,
//count:function(state){ return state.count }
countAlias:'count', // 别名
countPlusLocalState(state){ return state.count + this.countAlias }
})
}

// 对象展开运算符
computed:{
localComputed(){ },
...mapState({})
...mapState([])
}

Getters计算属性

  • getter 在 store 中定义“getter”(可以认为是 store 的计算属性 或者是公共的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算 公共的计算属性 全局计算属性
  • 定义
    • getters:{ xxx: (state)=> { return state.count }}
    • getters:{ xxx: (state,getters)=> { return getters.length }}
  • 使用
    • this.$store.getters.xxx 全局store上的计算属性
    • getters.xxx mapGetters传递到组件
  • 传递
    • mapGetters 传递 辅助函数 将 store中的getter映射到局部计算属性
      • computed:mapGetters({}//['xxx'])
      • computed:{ ...mapGetters({}//[]) }
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//store/index.js
state:{
todos:[
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters:{
// doneTodos 方法
doneTodos:state => {
return state.todos.filter(todo => todo.done)
}
}
// 接受其他 getter 作为第二个参数
getters:{
doneTodosCount:(state,getters) => {
return getters.doneTodos.length
}
}
// 通过属性访问
store.getters.doneTodosX

// vue组件使用
computed:{ // 使用
doneTodosCount(){
// return this.$store.state.todos
return this.$store.getters.doneTodosCount // 所以用名和getter名一致
}
}

// 通过方法使用
getters: {
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
// 通过方法访问时,每次都会去进行调用,而不会缓存结果
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

// 使用多个计算属性
import { mapGetters } from 'vuex'
export default{
computed:{
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([ // 下面没有试镜
'doneTodosCount', // getters
'anotherGetter', // getters
// 将一个 getter 属性另取一个名字,使用对象形式
donceCount:'doneTodosCount'
])
}
}

mutations同步变更

  • 变更commit变更状态 同步函数

定义

  • SOME_MUTATTION(state,payload){ return xxx }
  • SOME_MUTATTION:(state,payload) =>{ return }
  • [SOME_MUTATTION](state,payload){ } 常量名名加[]

使用 methods:{ xxx(){ } }

  • this.$store.commit('xxx') 全局使用
  • ``this.commit(‘xxx’,100)//({ type:xxx })//(‘xxx’,{})` 搭配mapMutaion局部使用

传参

  • mapMutaion

    • 使用多个值 使用mapMutations 辅助函数将组件中的methods 映射为 store.commit 调用(需要在根节点注入store)
    • methods:mapMutation(['',''])
    • methods:{ ...mapMutation([add:'increment']) }
      • 提交载荷(Payload)载荷(传入额外的参数) 载荷 == 参数
  • 常量代替Mutation 事件类型 mutation-type.js文件

1
2
3
4
5
6
7
8
9
const mutations = {
increment:state => state.count++
increment:function(state){ }
decrement:state => state.count--
}

export default createStore({
mutations
})
  • 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 使用 载荷是数值
store.commit("commit",100)

// 使用 载荷是对象 对象风格的提交方式有两种
// commit 样式一
store.commit('increment',{
amount:10
})

// 提交 mutation 的另一种方式是直接使用包含 `type` 属性的对象
store.commit({
type:'increment',
amount:10
})
  • 载荷(第二个参数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 大多数情况下,载荷(参数)应该是一个对象,这样可以包含多个字段并且记录mutation会更易读
mutations:{
increment(state,payload){
state.count += payload.amount
}
}
// commit 样式一
store.commit('increment',{
amount:10
})

mutations:{
increment(state,n){
state.count += n
}
}
store.commit("increment",10)
  • mapMutaion(传递多个Mutaion)
1
2
3
4
5
6
7
8
9
10
11
12
13
// mapMutations
import { mapMutations } from 'Vuex'

methods:{
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// `mapMutations` 也支持载荷:
'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
]),
...mapMUtations([
add:'increment' // b别名 将 `this.add()` 映射为 `this.$store.commit('increment')`
])
}
  • mutation-type 把mutation中的常量抽离出来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// mutation-type.js 抽离常量
export const SOME_MUTATTION = 'SOME_MUTATION'
export const ADD = 'ADD'

// mutation.js
import { SOME_MUTATION } from './mutation-type' // 导入常量
mutations:{
// 使用 三种方式
SOME_MUTATTION(state,payload){ return xxx }
SOME_MUTATTION:(state,payload) =>{ return }
[SOME_MUTATTION](state,payload){ } 使用ES2015风格的计算属性命名功能来使用一个常量作为函数名
// state.count = 1000
[ADD](state){ return state.count + 100 }
}

// xxx.vue 使用
import { mapMutations } from 'Vuex'

method:{
// 传递多个值
...mapMuations({ xxx:'SOME_MUTATTION'//别名,add:'ADD' }/['SOME_MUTATTION']),
clickFuc:()=> { this.$store.commit(add) }
}

Actions变更Mutaions异步

Action的作用 提交mutations

Action 类似 mutation 不同在于

  • Action提交的是mutation而不是直接变更状态 变更mutaions 解决 mutation是同步函数的缺陷
  • Action可以包含任意异步操作

定义

  • mutation:[increment](state){ return state.count++ }
  • action
    • 处理多步mutations
      • context:action:{ increment(context){ context.commit('increment') } } context.commit 结构赋值
      • 推荐:{commit}:actions:{ increment:({ commit }){ commit('increment') } }
    • 处理异步操作
      • incrementAsync({commit}){ setTimeout(()=>{},3000) }

使用

  • this.$store.dispatch('xxx') 全局使用
  • this.dispatch.xxx() 搭配mapActions局部使用

传参

  • mapActions
    • Actions 支持同样的载荷方式和对象方式进行分发:
    • methods:{ ...mapActions({ }//[]) } methods:mapActions({ }//[]) }
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// store.js
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
[increment](state){
state.count++
}
},

// Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 `context.commit` 提交一个 mutation,或者通过 `context.state` 和 `context.getters` 来获取 state 和 getters
// context
actions:{
increment(context){
context.commit('increment')
// mutation $store.commit('increment')
// action context.commit('increment')
}
}
// es2015
actions:{
increment:({ commit }){
commit('increment')
}
}
})

// 分发Action 通过`store.dispath方法触发
this.$store.dispatch('increment')

// `store.dispatch` 可以处理被触发的 action 的处理函数返回的 Promise,并且 `store.dispatch` 仍旧返回 Promise
action:{ // action 异步操作
incrementAsync({commit}){
setTimeout(()=>{
commit('increment')
},1000)
}
}

// xxx.vue
import { mapActions } from 'vuex'
export default{
methods:{
...mapActions:({
'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
}),
}
}`

vuex工程化

Module模块划分

类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const moduleA = {
state:() => ({...}),
mutations:{...},
actions:{ ... },
getters:{ ... }
}
const store = new Vuex.Store({
modules:{
a: moduleA,
b: moduleB
}
})
store.state.a --> moduleA 的状态
store.state.b --> moduleB 的状态
1
2
3
4
new Vuex.Store({
strict:true
strict:process.env.NODE_ENE !== 'production'
})

五文件划分

1
2
3
4
5
6
7
8
9
10
store/
--index.js
--getters.js
--actions.js
--mutations.js
--muations_type.js // 该项为存放mutaions方法常量的文件
// 更复杂 功能模块划分
--module
----cart.js
----products.js
1
2
3
4
5
mutaions 和 actions 层 负责将getter 的 计算属性 变更到 state 上
- 方法名(state,值){}
- `state.goods.totalPrice = this.getters.totalPrice`
- `this.commit(‘result’,’msg’)`
- state ==> mutations 、actions ==> getter

父子组件通信

父子

  • 父子 子props父标签属性 子 props:["xxx"] 父 <son :xxx="100"><son>

子父