Vue中使用vuex超详解

Vuex是什么?

Vuex是一个专为Vue.js应用程序开发的状态管理模式

它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

什么是状态管理模式

包含以下几个部分:

  • state,驱动应用的数据源
  • view,以声明方式将state映射到视图
  • actions,响应在view上的用户输入导致的状态变化

以下是一个表示“单向数据流”理念的简单示意:

`Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
在这里插入图片描述

store(仓库)

每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

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

由于 store 中的状态是响应式的,在组件中调用 store 中的状态简单到仅需要在计算属性中返回即可。触发变化也仅仅是在组件的 methods 中提交 mutation。

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 中的数据
            },
            data2 () {
                return this.$store.getters.xxx  // 获取 getters 中的数据
            }
        }
    }
    
  • 方案三:在 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'])
        }
    }
    
    // 调用时只需 mutation1(payload) 即可触发
    

mapState mapGetters 是用在 computed 上的

mapMutations mapActions 是用在 methods 上的

异步修改 state 数据

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

context !! 当前上下文对象,一般就理解为当前 store 的实例

 SYNCSETCURCITY(context, payload) {*

  *//      setTimeout(() => {});*

  *//     },*

一般就理解为当前 store 的实例

     通过它能获取 context.state   获取 state

         context.getters  获取 getters

           context.commit()  提交 某个mutation

             context.dispath() 派发 某个action

  一般 context 会使用结构赋值的方式去使用

   payload   触发这个 action 时传递过来的参数
  • 异步修改 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'])
        }
    }
    
    // 调用时只需 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'])
      }
      
    仓库模块的局部状态

    仓库模块做了拆分以后,getter与muration中的第一个参数是state是当前模块的局部state。

    action中的第一个参数context.context中的state也是当前模块的布局state

    有时我们需要在getter中action中去获取到其余模块的state数据

    getter的语法
    getters:{
        //state - 当前模块的state
        //getters- 当前模块的getters
        //rootState - 根模块的state数据,根据他就可以方便的去获取到其余模块的state
        getter1(state,getters,rootState){
        
        }
    }
    
    action 的语法
    action :{
        //context 是一个对象,这个对象有一些属性
        //state - 当前模块的state
        //getters- 当前模块的getters
        //commit - 提交mutation的方法
        //dispath - 派发action的方法
        //rootState - 根模块的state数据,根据他就可以方便的去获取到其余模块的state
        getter1(commit,payload){
    }
    }
    
       !mutation没有rootState这个东西
    

参考文档

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值