Vuex使用及理解

671 阅读3分钟

Vuex数据管理

如何理解数据管理?

这个Vuex就是vue中的数据管理中心 ,相信看过亮剑的大家都知道 ,本来独立团老李管理独立团那是想喝酒喝酒想吃肉吃肉 ,想打仗打仗,但这样的独立团就是比较混乱啊,就是和我们的vue一样 如果数据,都在data里边随取随用,那也一样很混乱,所以我们就需要一个单独的数据中心。也就是赵刚赵政委来了,管独立团的生活了,政委管生活,团长管打仗 ,这样分工也就比较明确。Vuex就是我们的政委。 来吧我们的资料数据管理,任何的管理都不能直接操作,而通过Vuex来统一的调配和转发。

管理不断变化的 state 非常困难。如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。-- 摘自《 Redux 中文文档 》

  1. 起步安装

    npm install vuex --save  
    
  2. 核心概念

    • store : 我们的数据管理中心 ,任何的操作都需要通过store ,也就是我们的赵政委
    • state :就是我们存储数据的地方
    • mutations : 我们修改数据都需要通过 mutations 来进行操作
  3. 使用

    • 新建store.js

      import Vuex from 'vuex';
      import Vue from 'vue';
      Vue.use(Vuex);  // 虽然和我们的router使用类似但我们不能在main.js中use
      export default new Vuex.Store({
          state:{
              count:0
          }
      })
      
    • main.js中使用 将我们的store.js 挂载到我们的原型链之上

      import Vue from 'vue'
      import App from './App.vue'
      import VueRouter from 'vue-router';
      import router from './routes';
      import store from './store';
      Vue.config.productionTip = false;
      Vue.use(VueRouter); //将this.$router 挂载到原型链上,使得vue具有处理路由的能力
      
      new Vue({
          router,
          store, // 相当于把我们的store挂载到原型链之上
          render: h => h(App),
      }).$mount('#app');
      
    • 数据使用 在.vue中使用this.$store来获取

      <script>
          export default {
              name: "Page2",
              computed:{
                  count(){
                      return this.$store.state.count
                  }
              }
          }
      </script>
      
  4. 当我们在对state的数据进行修改的时候,你一定想这样 ---直接修改

    仔细想想这样修改的话不是又回到了我们原来那种 更改state 其他组件也相应,最后你想找到问题来源或者添加新功能时变得困难那种状态了么?

    <script>
        export default {
            name: "Page2",
            created(){
                setTimeout(()=>{
                    this.$store.state.count++
                },2000)
            },
        }
    </script>
    

    ---解决使用vuex的严格模式使用,使用 mutations修改数据

    //--------------store.js中
    export default new Vuex.Store({
        state:{
            count:0
        },
        strict:true  //使用严格模式
    })
    
    
  5. 使用mutations修改数据

    在vuex中,关于修改state的方式,需要commit提交mutation。官方文档中有这么一句话:

    更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

    export default new Vuex.Store({
        state:{
            count:0
        },
        mutations:{
          increment(state){
              state.count++
          }
        },
        strict:true  //使用严格模式
    })
    
    // 相当于我们现在不能直接去获取物资了,得去政委那等级一下子才能获取物资 
    created(){
         setTimeout(()=>{
             // this.$store.state.count++
             this.$store.commit('increment')          
         },2000)
     },
    
  6. 上边其实是两种修改state的方式

    • 在vuex官方文档上看到了关于严格模式的描述

      开启严格模式,仅需在创建 store 的时候传入 strict: true; 在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

    • 于是,将vuex设置成了严格模式。

      直接修改state发现控制台确实是报出了错误,但是state修改成功,并且依然是响应式的。错误提示:

      Do not mutate vuex store state outside mutation handlers.

      • 通过commit 提交 mutation 的方式来修改 state 时,vue的调试工具能够记录每一次state的变化,这样方便调试。但是如果是直接修改state,则没有这个记录。
    • 分析源码

      • mutation通过commit修改state ,可以看到通过this._withCommit函数处理

      • 看_ withCommit ,_ withCommit函数的参数是fn 也就是我们上边的更改state的函数,在执行fn之前 ,将this.comiting =true ,等fn执行完 ,再将this. _commiting = commiting

      • 那么这个commiting和 严格模式的strict:true 设置有什么关系

      • enableStrictMode() 干了什么 ?

        在 enableStrictMode 函数内部,调用了 $watch 函数来观察 state的变化。当state变化时,就会调用 assert 函数,判断 store. _commiting( 上边的 this.committing) 的值,如果不为 true,就会报出异常:

      • 所以通过外部直接修改state,则没有执行 commit 函数,也就没有执行 withCommit 函数,进而 this. _ withCommitting 的值 不为 true,故当执行 enableStrictMode 时,则会执行 assert 函数,因为_withCommitting不为true,则报出异常了。

  7. getters :Vuex内部也需要 computed这个功能 ,比如将数据格式化

    有时候我们需要从store中的state中派生出一些状态 ,可以理解为vuex中数据的computed功能

    //--------------store.js
    getters:{
        money:state => `${state.count*1000}`
    },
    
    
    //--------------.vue 文件中 
    computed:{
        money(){
            return this.$store.getters.money
        }
    }
    
    
  8. Action :修改数据

    但是Mutations必须是同步的,Action是异步的Mutation,配合dispatch使用,定义上是一个异步的任务 ,大部分的任务 包括网络请求,网络数据的获取、文件的读取全部是异步的使用dispatch

    //--------------.vue文件中 
     created(){
     // setTimeout(()=>{
     //     // this.$store.state.count++
     // },2000)
         this.$store.dispatch('incrementAsync')  //在incrementAsync内部我们再去执行我们的异步操作
         this.$store.dispatch('incrementAsync',{ //还可以加参数
             num:10
         })
     },
    
    
    //--------------store.js
    mutations:{
        increment(state,args){
            state.count+= args.num || 1  //加参数后的变化
        }
    },
    actions:{
        incrementAsync(store,args){
            setTimeout(()=>{
                store.commit('increment',args);//在去执行Mutations的任务,args参数
            },2000)
        }
    },
    
    
  9. mapState

    当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会使得代码冗余和重复

    为了解决这个问题使用mapState辅助函数帮助我们生成计算属性

    computed:{
        count(){
            return this.$store.state.count
        },
        ...  //还有一堆的属性  
    }
    
    
    computed:{
        ...mapState({
            count:state=>state.count
        })
        // count(){
        //     return this.$store.state.count
        // }
    }
    
    
  10. mapActions

    和mapState类似 ,把actions方法映射进来

    created(){
        // this.$store.dispatch('incrementAsync',{ //还可以加参数
        //     num:10
        // });
        this.incrementAsync({  //直接使用这个更优雅 、更像组件内部的代码
            num:10
        })
    },
    methods:{
         ...mapActions(["incrementAsync"])
     },
    
    
  11. mapMutations

    聪明的你也一定和我一样想到了mapMutations

    setTimeout(()=>{
        this.increment({num:1})
    },2000)
    
     methods:{
         ...mapMutations(["increment"])
     },
    
    
  12. 总结一下

    State:用来存状态。在根实例中注册了store 后,用 this.$store.state 来访问。

    Getters:从 state 上派生出来的状态。可以理解为基于 State 的计算属性。很多时候,不需要 Getters,直接用 State 即可。

    Mutations:用来改变状态。需要注意的是,Mutations 里的修改状态的操作必须是同步的。在根实例中注册了 store 后, 可以用 this.$store.commit('xxx', data) 来通知 Mutations 来改状态。

    Actions:通过调用 Mutations 来改状态。Actions 可以包含异步操作。在根实例中注册了 store 后, 可以用 this.$store.dispatch('xxx', data) 来存触发 Action。

  13. Vuex完整数据流程