• 【前端vue面试】vuex


    什么是 Vuex?

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

    vuex流程图

    在这里插入图片描述

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

    • Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
    • 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

    State

    提供唯一的公共数据源,所有共享的数据统一放到store的state进行储存,相似与data

    import Vue from 'vue'
    import Vuex from 'vuex'
     
    Vue.use(Vuex)
     
    export default new Vuex.Store({
      state: {
        name:"张三",
        age:12,
        count:0
      },
    })
    
    //调用
    this.$store.state.count
    
    //template中直接用
    <div>{{$store.state.count}}</div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态

    mapState

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

    import { mapState } from "vuex";
    ...
    computed: mapState({
          // 箭头函数可使代码更简练
          name: state => state.name,
    
           // 传字符串参数 'age' 等同于 `state => state.age`
          age: 'age',
    
          // 为了能够使用 `this` 获取局部状态,必须使用常规函数
          countPlusAge (state) {
            return state.age + this.count
          }
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

    computed: mapState([
      // 映射 this.age 为 store.state.age
      'age',
       // 映射 this.name 为 store.state.name
      'name'
    ])
    // ===等同于===
    computed:  mapState({age:'age', name: 'name'})
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    与局部计算属性混合使用

    computed: {
      localComputed () { /* ... */ },
    
      // 使用对象展开运算符将此对象混入到外部对象中
      ...mapState({
        // ...
      })
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Getter

    Vuex 允许我们在 store 中定义 “getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter
    的返回值会根据它的依赖被缓存起来,而且只有当它的依赖值发生了改变才会被重新计算。 学会使用 Getter 可以避免我们重复的通过 state
    获取数据。

    Getter 接受 state 作为其第一个参数,我们可以对 state 中的数据做相应的处理,最终返回我们想要的数据:

    //vuex
    getters: {
          skillList: state => {
            return state.skill.filter(item => item.type === 1)
          }
        }
    
    //页面
    computed: {
          skillList() {
            return this.$store.getters.skillList
          }
        }   
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Getter 也可以接受其他 getter 作为第二个参数:

    getters: {
          skillList: state => {
            return state.skill.filter(item => item.type === 1)
          },
          skillCount: (state, getters) => {
            return getters.skillList.length
          },
        }
    
    computed: {
          skillList() {
            return this.$store.getters.skillList
          },
          count() {
            return this.$store.getters.skillCount
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    getter 除了可以直接返回数据之外,也可以通过让 getter 返回一个函数,来实现给 getter 传参。在对 store 里的数组进行查询时非常有用。

    getters: {
          skillList: state => (type) => {
            return state.skill.filter(item => item.type === type)
          },
          skillCount: (state, getters) => (type) => {
            return getters.skillList(type).length
          },
        }
    
    computed: {
          skillList() {
            return this.$store.getters.skillList(2)
          },
          count() {
            return this.$store.getters.skillCount(2)
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

    computed: {
          ...mapGetters([
            'skillList',
            'skillCount'
          ])
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Mutation

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

      state: {
        count: 1
      },
      mutations: {
        increment (state) {
          // 变更状态
          state.count++
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    触发 mutation

    store.commit('increment')
    
    
    • 1
    • 2

    你可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):

    mutations: {
      incrementByCount (state, n) {
        state.count = state.count + n
      }
    }
    
    
    store.commit('incrementByCount', 10)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在大多数情况下,载荷应该是一个对象,我们通常接收的参数命名为 payload,这样可以包含多个字段并且记录的 mutation 会更易读:

    // 定义 mutation
    mutations: {
      incrementByCount (state, payload) {
        state.count = state.count  + payload.count
      }
    }
    // 触发 mutation
    store.commit('incrementByCount', {
      count: 10
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对象风格的提交方式

    store.commit({
      type: 'incrementByCount',
      count: 10
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    mapMutations

    mapMutations 接收数组格式的参数

    ...mapMutations([
      // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
      'increment'
    ]),
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    mapMutations 接收对象格式的参数

    ...mapMutations({
      [别名]: [Mutation type] 
    })
    ...mapMutations({
      add: 'increment'
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Action

    Action 类似于 Mutation,不同的是:

    • Action 提交的是 mutation,而不是直接变更状态。
    • Action 可以包含任意异步操作。在 vuex 的使用过程中,我们可以将多个 Mutation 合并到一个 Action 中,也可以通过 Action 进行异步操作。

    基础用法

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

      state: {
        count: 1
      },
      mutations: {
        increment (state) {
          state.count++
        }
      },
      actions: {
        // 同步 action
        increment (context) {
          context.commit('increment')
        },
        // 异步 action
        incrementAsync (context) {
          setTimeout(() => {
            context.commit('increment')
          }, 1000)
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

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

    actions: {
      increment ({ commit }) {
        commit('increment')
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    dispatch

    Action 通过 store.dispatch 方法分发 Action

    store.dispatch('increment')
    
    
    • 1
    • 2

    提交载荷(Payload)

    你可以向 store.dispatch 传入额外的参数,即 Actions 的 载荷(payload):

    action: {
      increment ({commit}, payload) {
        // 具体 action 内容
      }
    }
    
    
    store.dispatch('increment', {count: 10})
    
    //对象风格的提交方式
    store.dispatch({
      type: 'increment',
      count: 10
    })
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    mapActions

    mapActions 辅助函数帮助我们简化提交 action 的写法。

    //mapActions 接收数组格式的参数
    ...mapActions([
      // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
      'increment'
    ]),
    
    
    //mapActions 接收对象格式的参数
    //在某些情况,我们需要对 Action 中的函数名重命名以避免和组件内部的变量冲突,这时候我们可以使用对象的方式接收参数:
    ...mapActions({
      [别名]: [Action name] 
    })
    // 例:将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    ...mapActions({
      add: 'increment'
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    组合 Action

    Action 通常是异步的,有时候我们需要知道 action 什么时候结束,并在结束后进行相应的其他操作。更重要的是,我们可以组合多个 action,以处理更加复杂的异步流程。
    首先,你需要明白 store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise:

    actions: {
      actionA ({ commit }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            commit('someMutation')
            resolve()
          }, 1000)
        })
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    现在我们可以:

    store.dispatch('actionA').then(() => {
      // ...
    })
    
    
    • 1
    • 2
    • 3
    • 4

    在另外一个 action 中也可以:

    actions: {
      // ...
      actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
          commit('someOtherMutation')
        })
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    最后,如果我们利用 async /await,我们可以如下组合 action:

    // 假设 getData() 和 getOtherData() 返回的是 Promise
    actions: {
      async actionA ({ commit }) {
        commit('increment', await getData())
      },
      async actionB ({ dispatch, commit }) {
        await dispatch('actionA') // 等待 actionA 完成
        commit('increment', await getOtherData())
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Modules

    当遇见大型项目时,数据量大,store就会显得很臃肿

    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 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 的状态
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    A-Level经济真题(12)
    泛微E-Cology CheckServer.jspSQL注入漏洞(QVD-2023-9849) 复现
    [附源码]计算机毕业设计JAVA学生量化考核管理系统
    photoshop如何使用PS中的吸管工具吸取软件外部的颜色?
    “就地拼柜”与“海外仓”:跨境电商的黄金组合
    <三>使用类模板实现STL Vector
    Qt Core篇 后端上位机界面开发
    opencv dnn模块 示例(25) 目标检测 object_detection 之 yolov9
    Unity Meta Quest 开发:与 Unity 的 UI 系统进行交互
    基于订单流工具,我们能看到什么?
  • 原文地址:https://blog.csdn.net/qq_37215621/article/details/133963062