vuex快速入门

作者: 明灭_ | 来源:发表于2019-03-22 16:02 被阅读256次

    本文为课程 vuex深入浅出 的学习总结与记录;同时参照了vuex官方文档
    文中demo的代码可参考:我的码云


    一、概念

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

    • 不使用vuex的数据流:


      image.png
    • 使用vuex进行状态维护:


      image.png

    二、在项目中使用vuex

    可以通过以下步骤引入vuex

    1. 安装:npm install vuex --save
    2. 创建store目录,用来存放所有状态。大型项目的目录结构可能如下所示:
      image.png
      在此我们只创建一个store.js文件作为示例:
      state中存放的是唯一数据源
    import Vue from 'vue'
    import Vuex from 'vuex';
    
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({   // 注意Store的S大写
        state: {
            data1: ...,
            data2: ...
            ...
        }
    })
    
    
    1. main.js中添加如下代码:
    import {store} from '../store/index'
    
    new Vue({
      ...
      store,
      ...
    })
    

    三、核心概念介绍

    原课程是以小demo的形式讲解vuex,在此依同样方法做以记录。
    此demo有两个组件listOne.vuelistTwo.vueApp.vue为主组件。
    最终效果和初始代码(省略样式)如下:

    效果图
    store.js:
    import Vue from 'vue'
    import Vuex from 'vuex';
    
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({   // 注意Store的S大写
        state: {
            productList: [
                {name: 'goods 1',price: 100},
                {name: 'goods 2',price: 200},
                {name: 'goods 3',price: 300},
                {name: 'goods 3',price: 400}
            ]
        }
    })
    

    App.vue:

    <template>
      <div>
        <list-one/>
        <list-two/>
      </div>
    </template>
    
    <script>
    import listOne from './components/listOne.vue';
    import listTwo from './components/listTwo.vue';
    
    export default {
      name: 'App',
      components: {
        listOne, listTwo
      }
    }
    </script>
    

    listOne.vue:

    <template>
    <div class="list-one">
      <h1>list one</h1>
      <ul>
        <li v-for="(product, index) in productList" :key=index>
           <p>名称:{{product.name}}</p>
          <p>价格:{{product.price}}</p> 
        </li>
      </ul>
      <button>降价</button>
      <button>异步降价</button>
    </div>
    </template>
    
    <script>
      export default {
          data() {
              productList: this.$store.state.productList // 获取store.js > state > productList
          }
      }
    </script>
    

    listTwo.vue:

    <template>
      <div class="list-two">
        <h1>list two</h1>
        <ul>
          <li v-for="(product, index) in getProductList" :key=index>
            <p>名称:{{product.name}}</p>
            <p>价格:{{product.price}}</p> 
          </li>
      </ul>
    </div>
    </template>
    
    <script>
    import {mapGetters} from 'vuex'
    
    export default {
        data() {
              productList: this.$store.state.productList
        }
    }
    </script>
    
    核心概念1:state
    • statevuex的唯一数据源,是所有组件的公共data。中上述代码中,我们已经将两个组件的公共数据存入state。在组件中,使用this.$store.state.product获取state中的数据。
    • 如果需要获取多个state,可使用...mapState辅助函数。如下:
    import {mapState} from 'vuex;
    
    ...
    
    computed: {
       ...mapState([
          'productList',
          '...'
      ])
    }
    

    此时组件中修改如下:

    <li v-for="(product, index) in productList" :key=index>
    

    核心概念2:getters

    • getters用于从state中派生出一些状态,例如对列表进行过滤等。可以将getters理解为计算属性computedgetter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
    • getters接受state作为其第一个参数
    • 这时我们可以在store.js中添加一个getter属性:saleProducts,用于将商品价格除以2。
    // store.js:
    import Vue from 'vue'
    import Vuex from 'vuex';
    
    Vue.use(Vuex)
    
    export const store = new Vuex.Store({ 
        state: {
            productList: [
                {name: 'goods 1',price: 100},
                {name: 'goods 2',price: 200},
                {name: 'goods 3',price: 300},
                {name: 'goods 3',price: 400}
            ]
        },
        getters: {
            getSaledPrice: (state) => {
                let saleProduct = state.productList.map((item) => {
                    return {
                        name: '**' + item.name + '**',
                        price: item.price / 2
                    }
                })
                return saleProduct;
            }
        }
    })
    

    listOne.vue中的productList的值更换为this.$store.getters.getSaledPrice:

    // listOne.vue
    export default {
        data () {
            return {
                productList : this.$store.getters.getSaledPrice 
            }
        }
    }
    

    此时效果如下:(注意list one部分名称和价格的变动)

    image.png
    • 如果需要使用多个getters,可使用...mapGetters辅助函数。如下:
    computed: {
        ...mapGetters:([
            'getSaledPrice',
             ...
        ])
    }
    

    核心概念3:mutation

    • 更改vuexstore中的状态的唯一方法是提交mutationvuex中的mutation类似于事件:每个mutation都有一个字符串的事件类型和一个回调函数。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数(payload为第二个参数,也就是自定义参数)。
    • 在此我们给store添加一个mutation属性reducePrice,用于将商品价格减少payload
    // store.js
    mutations: {
        reducePrice: (state, payload) => {
            return state.productList.forEach((product) => {
                product.price -= payload;
            })
        }
    }
    
    // listOne.vue
    methods: {
        reducePrice(){
            this.$store.commit('reducePrice', 4)
        }
    }
    

    点击降价按钮,可以发现价格发生变化:


    image.png
    • 或使用mapMutations辅助对象:
    // listOne.vue
    <template>
        ...
        <button @click="reducePrice(4)">降价</button>
        ...
    </template>
    
    <script>
      .....
      methons: {
          ...mapMutations([
             'reducePrice'
          ])
      }
      .....
    </script>
    

    核心概念4:action

    • action类似于mutation,不同之处在于:
    1. action提交的是mutation,而不是直接变更状态。
    2. action可以包含异步操作,而mutation不行。
    3. actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象.
    4. action通过store.dispatch方法触发,mutation通过store.commit方法提交。
    • 在此我们添加一个action属性,用来进行异步降价操作(每隔2秒后改变价格)
    // store.js
    
    actions: {   // 提交的是mutation,可以包含异步操作
        reducePriceAsync: (context, payload) => {
            setTimeout(()=> {
                context.commit('reducePrice', payload);  // reducePrice为上一步mutation中的属性
            },2000)
        }
    }
    
    methods: {
      reducePriceAsync(){
            this.$store.dispatch('reducePriceAsync', 2)
       },
    }
    

    或使用mapActions辅助对象:

    // listOne.js
    
    <template>
        ...
        <button @click="reducePriceAsync(4)">异步降价</button>
        ...
    </template>
    
    <script>
      .....
      methons: {
         ...mapActions([
              'resducePriceAsync'
         ])
      }
      .....
    </script>
    

    核心概念5:module

    由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。

    image.png

    相关文章

      网友评论

        本文标题:vuex快速入门

        本文链接:https://www.haomeiwen.com/subject/ldxrvqtx.html