vuex 核心知识汇总

vuex 介绍

vuex 是什么

  • vue 官方提供的状态管理器,用于处理组件的数据共享问题

什么时候需要使用 vuex

  • 当多个组件需要共享状态的时候,使用 vuex 能更好的帮助我们管理这些需要共享的状态
    在这里插入图片描述

vuex 仓库(store)的五大核心

  • state :专门存储共享数据的地方
  • getters : 针对现有 state 数据或者其余的 getter 数据做二次计算的数据,可以理解为仓库的计算属性
  • mutations : 唯一能够修改 state 数据的地方,并且只能同步修改。
  • actions : 这里面可以写异步代码,如果如要修改 state 中的数据,必须通过调用 mutation 来修改
  • modules : 仓库模块的拆分

vuex 仓库中的四个辅助函数

  • mapState() 获取 state 中的数据
  • mapGetters() 获取 getters 中的数据
  • mapMutations() 获取 mutations 配置项中同步修改 state 中数据的方法
  • mapActions() 获取 actions 配置项中异步修改 state 中数据的方法

使用 vuex

  • 在项目中安装 vuex

    $ npm install vuex
    
  • 创建 src/store.js 文件,用来生成仓库的实例,并且生成的实例需要在 main.js 文件 new Vue() 中挂载

    以下代码在 store.js 文件

    // 引入 vue
    import Vue from 'vue'
    // 引入 vuex
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    // 创建仓库实例 
    const store = new Vuex.Store({
        state: {},
        getters: {},
        mutations: {},
        actions: {},
        modules: {}
    })
    
    // 暴露 store 
    export default store
    

组件中使用 state 与 getter

  • 方案一:使用挂载到 Vue 原型上的 $store 对象,这个 $store 就是 new Vue.Store() 生成的仓库实例对象

    // 直接在页面上使用时
    $store.state.xxx   ||  $store.getters.xxx
    
  • 方案二:在 computed 中使用

    export default {
        computed: {
            data1 () {
                return this.$store.state.xxx  // 获取 state 中 xxx 数据
            },
            data2 () {
                return this.$store.getters.xxx  // 获取 getters 中 xxx 数据
            }
        }
    }
    
  • 方案三:在 computed 中使用 辅助函数,辅助函数内部就是用上述方案二展开实现的

    // 使用 辅助函数必需先引入
    import { mapState, mapGetters } from 'vuex'
    export default {
        computed: {
            // mapState 接收一个数组做为参数,参数中的每一项,就是在仓库中的 state 数据
            ...mapState(['state', 'state2'])
            // mapGetters  接收一个数组做为参数,参数中的每一项,就是在仓库中的 getter 数据
            ...mapGetters(['getter1', 'getter2'])
        }
    }
    
    // 如果希望组件中数据与仓库中数据不同名,采用第二种方案即可
    

组件中修改 state 与 getter

注意:state 可以被修改,getter 不允许修改

  • 同步修改 state ,需要仓库中提供对应修改 state 的 mutation 函数

  • 方案一:使用 vuex 挂载到 vue 原型上的 $store 对象的 commit() 方法

    // 直接在页面上使用时
    $store.commit('updateNmae', payload)
    
  • 方案二:在 methods 中使用

    export default {
        methods: {
            fn (payload) {
                // updateNmae 是仓库中 mutations 配置相中定义的函数名称,payload 传递过去的参数
                this.$store.commit('updateName', payload)
            }
        }
    }
    
  • 方案三:在 methods 中使用 辅助函数,辅助函数内部就是用上述方案二展开实现的

    // 使用 辅助函数必需先引入
    import { mapMutations } from 'vuex'
    export default {
        methods: {
            // mapMutations  接收一个数组做为参数,参数中的每一项,就是在仓库中的 mutation 方法
            ...mapMutations(['mutation1', 'mutation2'])
        }
    }
    
    // 调用时只需 this.mutation1(payload) 即可触发
    

异步修改 state 数据

mutation 里面只允许同步的去修改 state 数据。(虽然在mutation中可以异步的去修改state数据不会报错,但是会导致时间旅行等机制没有效果)

  • 异步修改 state ,需要仓库中提供对应修改 state 的 action 函数

  • 方案一:使用 vuex 挂载到 vue 原型上的 $store 对象的 dispatch() 方法

    // 直接在页面上使用时
    $store.dispatch('actionName', payload)
    
  • 方案二:在 methods 中使用

    export default {
        fn (payload) {
            setTimeOut(() => {
                this.$store.dispatch('actionName', payload)
            }, 1000)
        }
    }
    
  • 方案三: 在 methods 中使用 辅助函数,辅助函数内部就是用上述方案二展开实现的

    // 使用 辅助函数必须先引入
    import { mapActions } from 'vuex'
    export default {
        methods: {
            // mapActions  接收一个数组做为参数,参数中的每一项,就是在仓库中的 action 方法
            ...mapActions(['action1', 'action2'])
        }
    }
    
    // 调用时只需 this.action1(payload) 即可触发
    

注意辅助函数的书写:mapState()、mapGetters() 书写在组件的 computed 配置项中,mapMutations()、mapActions() 书写在组件的 methods 配置项中

注意:为什么 vuex 中的 state 必须使用 mutation 来是修改:

  1. 为了以一种可以预见的方式去修改数据,不至于让数据难以理解

  2. 为了实现时间旅行

vuex 中的 module

  • 什么时候需要在 vuex 中使用 module
    • 项目越做越大,功能点越写越多。需要使用 vuex 共享的数据越来越庞大时,就需要使用 module 来进行仓库模块拆分,拆分的每个模块都拥有自己的 state、mutation、action、getter,甚至是嵌套子模块
    // 拆分的仓库 子模块A
    const moduleA = {
        state: { },
        mutations: { },
        actions: { },
        getters: { }
    }
                
    // 拆分的仓库 子模块B
    const moduleB = {
        state: { },
        mutations: { },
        actions: { }
    }
    
    // 仓库根模块
    const store = new Vuex.Store({
    	// 通过 modules 配置选项将拆分出去的子模块配置到根仓库中
    	modules: {
            aa: moduleA,
            bb: moduleB
        }
    })
    
    store.state.aa // -> moduleA 的状态
    store.state.bb // -> moduleB 的状态
    
  • 仓库拆分子模块后,没有设置命名空间引起的问题

    默认情况下,模块内部的 getter、mutation 、action是注册在全局命名空间

    • 多个子模块中的 getter 不能同名,否则会报错
    • 多个子模块中的 mutation 如果同名的话,组件调用这个 mutation 时,都会被触发,会引起全局污染
    • 多个子模块中的 action 如果同名的话,组件调用这个 action 时,都会被触发,会引起全局污染
  • 由于上述问题,需要给每个子模块设置命名空间
    • 给每个子模块的对象配置中添加一个 namespaced 属性即可,属性值为 true

      // 拆分的仓库 子模块A
      const moduleA = {
          namespaced: true,  // 给子模块设置命名空间
          state: { },
          mutations: { },
          actions: { },
          getters: { }
      }
      
    • 设置后,子模块中的 getter、mutation、action 是注册在自己命名空间

  • 设置了命名空间后,使用的时候需要加上仓库的名称
    • 获取某个仓库子模块中的 state

      // 1.直接页面上获取时
      $store.state.xxx.stateKey  // xxx 代表仓库子模块的名称
      
      // 2.使用计算属性
      computed: {
          data () {
              return this.$store.state.xxx.stateKey
          }
      }
      
      // 3.使用辅助函数 mapState()
      computed: {
          ...mapState('xxx', ['state1', 'state2']) // 原理:使用上述计算属性展开的
      }
      
      // 注意:如果在组件中同时拿多个仓库子模块的同名 state 数据,应使用上面计算属性的方式
      
    • 获取某个仓库子模块中的 getter

      // 1.页面上直接使用
      $store.getters['xxx/getterKey']
      
      // 2.使用计算属性
      computed: {
          data () {
              return this.$store.getters['xxx/getterKey']
          }
      }
      
      // 3.使用辅助函数 mapGetters()
      computed: {
          ...mapGetters('xxx', ['getter1', 'getter2'])
      }
      
    • 提交摸个仓库子模块中的 mutation

      // 1.页面上直接使用
      $store.commit('xxx/mutationKey', payload)
      
      // 2.自定义函数中使用
      methods: {
          fn (payload) {
              this.$store.commit('xxx/mutationKey', payload)
          }
      }
      
      // 3.使用辅助函数 mapMutations()
      methods: {
          ...mapMutations('xxx', ['mutation1', 'mutation2'])
      }
      
    • 派发某个仓库子模块中的 action

      // 1.页面上直接使用
      $store.dispatch('xxx/actionKey', payload)
      
      // 2.自定义函数中使用
      methods: {
          fn (payload) {
              this.$store.dispatch('xxx/actionKey', payload)
          }
      }
      
      // 3.使用辅助函数 mapActions()
      methods: {
          ...mapActions('xxx', ['action1', 'action2'])
          // OR 
          ...mapActions({
          	xxx: 'xxx/action1',
          	yyy: 'xxx/action2'
          })
      }
      
  • 仓库拆分子模块后,各子模块间的状态获取 (只能在 getter 与 action 中获取)
    • 在 getter 中获取,根节点状态会作为第三个参数暴露出来

      const moudelA = {
          getters: {
              getter1 (state, payload, rootState) { // rootState 就是根节点状态
                  console.log(rootState) // 只能读取
              }
          }
      }
      
    • 在 action 中获取,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState

      const moduleA = {
          actions: {
              action1 ({ state, commit, rootState }) {
                  console.log(rootState) // 只能读取
              }
          }
      }
      
  • v-model 指令与 store 仓库数据双向绑定

    • 不用指令时

      <input :value="message" @input="updateMessage">
          
      computed: {
        ...mapState(['message'])
      },
      methods: {
        updateMessage (event) {
            this.$store.commit('updateMessage', event.target.value)
        }
      }
      
    • 使用 v-model 指令时

      <input v-model="message">
          
      computed: {
          message: {
              get () {
                  return this.$store.state.message
              },
              set (value) {
                  this.$store.commit('updateMessage', value)
              }
          }
      }
      
  • 学习更多:vuex 官网

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值