美文网首页Vue
vue - vuex 使用进阶(一)

vue - vuex 使用进阶(一)

作者: Qingelin | 来源:发表于2020-09-10 14:51 被阅读0次

    目录:

    • 核心概念使用方法及场景:
      • state
      • mutations
      • actions
      • getters
    • 多页面公用vuex实例
      • 在页面中调用后端接口展示数据案例

    参考链接:
    vuex简介
    vue.js的状态管理vuex中store的使用
    理解vuex,看这篇就够了


    本文中不再详细介绍vuex基本概念和用法,若想详细了解请参考第一链接!

    1. 核心核心概念使用方法及场景:

    1.1 state

    单一状态管理树,只有在这里声明我们需要的数据类型和值,才能在vue组件中获取定义的对象的状态。

    1.2 mutations

    mutations翻译是更改,更改store中state中的状态值的唯一方法就是提交mutations,每一个mutations都有一个字符串类型的事件类型和回调函数,执行这个回调调函的方法有三个,本质上是一个:提交mutations,即commit mutations,提交时附加一些payload数据,叫做负荷。

    • 基本用法:
    mutations:{
     increment(state,payload){
       state.count = payload.number  //这里改变state中的数据
     }
    }
    

    ① 在actions中commit(回调函数名,payload),具体使用情况看下面的案例.

    ② 在组件中methods里this.$store.commit(回调函数名,payload).

    ③ 在组件中使用mapMutations辅助函数将组件中的mutatios映射为this.$store.commit("回调函数名",{传入的第二个}).

    1.3 actions
    • 1.3.1 actions基本用法:
      actions很多地方都和mutations用法类似,最大的不同就是actions可以是异步函数,但mutations必须是同步函数,而且actions不能直接修改state,是通过commit mutations(上一内容)来改变state.声明actions时它接受的第一个参数就是和state有相同方法和属性的context对象,第二个参数也是payload。触发actions的方法:
      ① 在actions通过context.commit(mutations中回调函数名,payload)

    ② 在组件中methods里分发:this.$store.dispatch("mutations中回调函数名",{payload})

    ③ 使用 mapActions辅助函数,将组件中的methods映射为this.$store.dispatch调用

    export default{
      methods:{
        ...mapActions([
            'mutations的回调函数名'
        ])
      },
    /* ----------或者-----------*/
      ...mapActions({
          页面展示用的名称 : 'mutations的回调函数名'
      })
    }
    
    • 1.3.2 actions嵌套用法:
      actions中可以是异步函数,这就使得actions中可以嵌套另外一个actions,即this.$store.dispatch()可以处理已经被触发得的actions得到的promise,处理后的结果仍返回promise对象。
      //组合性的异步嵌套actions的操作
    actions:{
      actionA({commit}){
          return new Promise((resolve,reject) =>{
              setTimeout(() => {
                  commit('someMutation')  //会把得到的数据保存到someMutation位置
              } ,10000)
          })
      }
    }
    
    //在某一个页面组件中触发:
     this.$store.dispatch("actionA").then(() => {
        //... 
    })
    
    //在另外一个actions中也可以这样写,actionB处理actionA被触发得到的Promise,再提交someOtherMutations
    actions:{
       //...
        actionB({diapatch,commit}){
            return dispatch('actionA').then(
                commit('someOtherMutations')  
            )
        }
    }
    
    • 再结合async await 优化组合actions的代码
    actions : {
      async actionA({commit} {
        commit('gotData',await getData())
      }),
      async actionB({dispatch,commit}){
        await dispatch('actionA')  //等待actionA执行完成后再执行
        commit('gotOtherData', await getOtherData)
      }
    }
    
    1.4 getters

    getter类似于Vue.js 的computed计算属性,当我们需要从state中派生一些状态就用getter函数,getter函数的第一个参数为state,还可以接受其他参数,而且它的返回值被缓存起来,只有当getter依赖值(state中的相关状态值)发生改变才会被重新计算。

    • 基本用法:
    getters:{
      doneTodos : {
          return state.todosfilter(todo => todos.count)
      }
    }
    
    • 在页面中触发getters的两种方法:
      1. 可以通过this.$store.getters.doneTodos方法可以访问得到这些派生出来的状态值
      2. 还可以使用辅助函数:
      export default{
            computed : {
               //当同时使用多个getter函数时可以这样写
                ...mapGetters([
                     'doneTodos',
                     'anotherGetters'
                ])
            }  
      }
      
    • 如果想给一个getters(doneTodos)再取一个名字,则使用对象形式
    export default{
          computed : {
              ...mapGetters({
                  anotherName: 'doneTodos'
              })
          }  
    }
    
    1.5 mudules

    当store太过于复杂的时候对它的一种切割,每一个module都有自己的state,mutation,action和getter

    moduleA = {
      state:{},
      mutations:{},
      actions:{},
    getters:{}
    },
    moduleB = {
      state:{},
      mutations:{},
      actions:{},
    getters:{}
    },
    const store new Vuex.Store({
      a : moduleA,
      b : moduleB
    })
    
    store.state.a // moduleA的状态
    store.state.b // moduleB的状态
    
    1.6 mudules局部状态
      1. 模块内部mutations 和getters
        对于模块内部的mutation和getter接受的第一个参数就是模块内部局部状态对象
      moduleA = {
        // ...
        state:{count:0},
        mutation : {
            increment(state){
            // 这里的state就是模块的局部状态
                state.count ++
            }
        },
        getters : {
            doubleCount(state){
                // 这里的state就是模块的局部状态
                return state.count * 2
            }
        }
      }
    
      1. 模块内部actions
        对于模块内部的actions,模块内部局部状态会通过 context.state方式暴露出来
        moduleA = {
          // ...
            actions : {
              increment({state,context}){
                    if(context.state.count % 2 === 1){
                        context.commit('increment')
                    }
               }
            }   
        }
    
      1. 根节点
        对于模块内部的getters和actions根节点的暴露方式:
      moduleA = {
        // ...
        //跟节点会通过第三个参数暴露出来
        getters : {
            sumWithRootCount(state,context,rootState ){
                return state.count + rooState.count
            }
        },
      //根节点状态会通过context.rootState暴露出来
        actions : {
          incrementRootSum(state,context,rootState){
              if(context.rootState.count % 2 === 1){
                  context.commit('incrementRootSum')
              }
           }
        }
      }
    
    1.7 vuex — 计算属性 — 实现双向绑定,使用带有setter的计算属性

    假设obj是计算属性返回的属于vuex store中的一个对象

    <input v-model="message">
    
    export default{
      //...
      computed:{
          message : {
              get(){
                  return this.$store.state.obj.message
              },
              set(value){
                  this.$store.commit('updateMessage',value)
              }
          }
      }
    }
    
    
    

    store中的mutaions:

      // ...
      mutatoins : {
           undateMessage(state,message){
              state.obj.message = message
          }
      }
    

    2. 移动端多页面公用vuex案例

    2.1 情景介绍:

    当前端开发调用后端接口获取数据,并在多个页面中展示数据时,任意组件之间通信,最好的方法就是使用vuex.

    2.2 使用方法:使用案例 https://github.com/vuejs/vuex/tree/dev/examples
    • 入口文件 : main.js
    import Vue from 'vue';
    import App from './components/App.vue';
    import store from './store';
    import { currency } from './currency'
    
    Vue.filter('currency',currency)
    
    var vm =  new Vue({
      el:'#app',
      store,
    render : h => h(App)
    })
    
    • 定义vuex .store: ./store/index.js中的代码
    import Vue from 'vue'
    import Vuex from 'vuex'
    import cart from './modules/cart'
    import products from './modules/products'
    import createLogger from '../../../src/plugins/logger'
    
    Vue.use(Vuex)
    
    export default new Vuex.store({
        modules:{
          cart,
          products
        }
    })
    
    • 创建两个module:
    1. ./store/modules/cart.js
    import shop from '../../api/shop'
    
    //初始化state
    const state = () => {
        items : [ ],
        checkoutStatus : null
    }
    
    
    //getters
    const getters = {
      cartProducts : (state,getters,rootState) =>{
          return state.item.map({id,quantity}) => {
              const product = rootState.prosucts.all.find(product => product.id === id)
                return {
                  title : products.title,
                  price : products.price,
                  quantity
                }  
          }
      },
    
        cartTotalProducts : (state,getters)=>{
            return getters.cartProducts.reduce((products,total)=>{
                return total = products.price * products.quantity
            },0)
       }
    }
    
    //mutations
    const mutations = {
        pushProductToCart(state,{id}){
          state.items.push({
              id,
              quantity : 1
          })
        } ,
      incrementItemQuantity (state, { id }) {
        const cartItem = state.items.find(item => item.id === id)
        cartItem.quantity++
      },
    
      setCartItems (state, { items }) {
        state.items = items
      },
    
      setCheckoutStatus (state, status) {
        state.checkoutStatus = status
      } 
    }
    
    
    //actions
    const actions = {
      checkout ({ commit, state }, products) {
        const savedCartItems = [...state.items]
        commit('setCheckoutStatus', null)
        // empty cart
        commit('setCartItems', { items: [] })
        shop.buyProducts(
          products,
          () => commit('setCheckoutStatus', 'successful'),
          () => {
            commit('setCheckoutStatus', 'failed')
            // rollback to the cart saved before sending the request
            commit('setCartItems', { items: savedCartItems })
          }
        )
    }
    
    1. ./store/modules/products.js
    import shop from '../../api/shop';
    //initial state
    const state = () => ({
        all : []
    })
    
    // mutations
    const mutations = {
      setProductss(state,products){
        state.all = products
      },
      decrementProductInventory(state,{id}){
        const product = state.all.find(product => product.id = id)
        product.inventory --
      }
    }
    
    //actions
    const actions = {
      getAllProducts({commit}){
        shop.getProducts(products =>{
            commit('setProducts',products)
        })
      }
    }
    
    //getters
    const getters = {
      
    }
    
    export default{
       namespaced = true,
       state,
       actions,
       mutations,
       getters
    }
    
    • 通信的组件:
    1. /component/App.vue
    <template>
      <div id="app">
        <h1>shopping cart example</h1>
        <hr>
        <h2>products example</h2>
        <ProductList/>
        <hr>
        <h2>cart example</h2>
        <ShoppingCart/>
      </div>
    </template>
    <script>
      import ProductList from './ProductList.vue';
      import ShoppingCart from './Cart.vue'; 
    
      export deafult{
          components:{
              ProductList,
              ShoppingCart
          }
      }
    </script>
    
    1. /component/ProductList.vue
    <template>
      <ul>
        <li v-for="product in products" :key="product.id">
          {{product.title}}-{{product.price | currency}}
          <button :disabled="product.inventory" @click="addProductToCart(product)">
              add to cart
          </button>
        </li>
      </ul>
    </template>
    <script>
    import { mapSate, mapActions } from "vuex"
    
    export default{
      // ...
      computed : ...mapState({
         products: state =>  state.products.all
      }),
      methods : ...mapActions('cart',[
       'addProductToCart' 
      ]),
      created(){
        this.$store.dispatch('products/getAllProducts')
      }
    }
    </script>
    
    1. /component/ShoppingCart.vue
    <template>
      <div class="cart">
        <h2>Your cart</h2>
        <p v-show="!products.length"><i>please add some products to cart.</i></p>
        <ul>
          <li v-for="product in products" :key="product.id">
              {{ product.title }} - {{ product.price | currency }} x {{ product.quantity }}
          </li>
        </ul>
        <p>Total:{{total | currency}}</p>
        <p><button :disabled="!product.length" @click="checkout(products)">checkout</button></p>
        <p v-show="checkoutStatus">Checkout{{checkoutStatus}}.</p>
      </div>
    </template>
    <script>
    import  { mapGetters, mapState }  from 'vuex';
    
    export default{
        computed : {
          ...mapState){
              checkoutStatus : state => state.cart.checkoutStatus
           }),
          ...mapGetters:('cart',{
              products : 'cartProducts',
              total : 'cartTotalProducts'
           })
        },
        methods : {
            checkout(products){
                this.$store.dispatch('cart/checkout', products)
            }
        }
    }
    </script>
    

    相关文章

      网友评论

        本文标题:vue - vuex 使用进阶(一)

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