vue - vuex 使用進(jìn)階(一)

目錄:

  • 核心概念使用方法及場(chǎng)景:
    • state
    • mutations
    • actions
    • getters
  • 多頁(yè)面公用vuex實(shí)例
    • 在頁(yè)面中調(diào)用后端接口展示數(shù)據(jù)案例

參考鏈接:
vuex簡(jiǎn)介
vue.js的狀態(tài)管理vuex中store的使用
理解vuex侦啸,看這篇就夠了


本文中不再詳細(xì)介紹vuex基本概念和用法,若想詳細(xì)了解請(qǐng)參考第一鏈接锐峭!

1. 核心核心概念使用方法及場(chǎng)景:

1.1 state

單一狀態(tài)管理樹窒舟,只有在這里聲明我們需要的數(shù)據(jù)類型和值写半,才能在vue組件中獲取定義的對(duì)象的狀態(tài)屿衅。

1.2 mutations

mutations翻譯是更改畅卓,更改store中state中的狀態(tài)值的唯一方法就是提交mutations,每一個(gè)mutations都有一個(gè)字符串類型的事件類型和回調(diào)函數(shù)擅腰,執(zhí)行這個(gè)回調(diào)調(diào)函的方法有三個(gè),本質(zhì)上是一個(gè):提交mutations,即commit mutations,提交時(shí)附加一些payload數(shù)據(jù)翁潘,叫做負(fù)荷趁冈。

  • 基本用法:
mutations:{
 increment(state,payload){
   state.count = payload.number  //這里改變state中的數(shù)據(jù)
 }
}

① 在actions中commit(回調(diào)函數(shù)名,payload)拜马,具體使用情況看下面的案例.

② 在組件中methods里this.$store.commit(回調(diào)函數(shù)名渗勘,payload).

③ 在組件中使用mapMutations輔助函數(shù)將組件中的mutatios映射為this.$store.commit("回調(diào)函數(shù)名",{傳入的第二個(gè)}).

1.3 actions
  • 1.3.1 actions基本用法:
    actions很多地方都和mutations用法類似俩莽,最大的不同就是actions可以是異步函數(shù)旺坠,但mutations必須是同步函數(shù),而且actions不能直接修改state,是通過commit mutations(上一內(nèi)容)來改變state.聲明actions時(shí)它接受的第一個(gè)參數(shù)就是和state有相同方法和屬性的context對(duì)象扮超,第二個(gè)參數(shù)也是payload取刃。觸發(fā)actions的方法:
    ① 在actions通過context.commit(mutations中回調(diào)函數(shù)名,payload)

② 在組件中methods里分發(fā):this.$store.dispatch("mutations中回調(diào)函數(shù)名"出刷,{payload})

③ 使用 mapActions輔助函數(shù)璧疗,將組件中的methods映射為this.$store.dispatch調(diào)用

export default{
  methods:{
    ...mapActions([
        'mutations的回調(diào)函數(shù)名'
    ])
  },
/* ----------或者-----------*/
  ...mapActions({
      頁(yè)面展示用的名稱 : 'mutations的回調(diào)函數(shù)名'
  })
}
  • 1.3.2 actions嵌套用法:
    actions中可以是異步函數(shù),這就使得actions中可以嵌套另外一個(gè)actions馁龟,即this.$store.dispatch()可以處理已經(jīng)被觸發(fā)得的actions得到的promise,處理后的結(jié)果仍返回promise對(duì)象崩侠。
  //組合性的異步嵌套actions的操作
actions:{
  actionA({commit}){
      return new Promise((resolve,reject) =>{
          setTimeout(() => {
              commit('someMutation')  //會(huì)把得到的數(shù)據(jù)保存到someMutation位置
          } ,10000)
      })
  }
}
//在某一個(gè)頁(yè)面組件中觸發(fā):
 this.$store.dispatch("actionA").then(() => {
    //... 
})
//在另外一個(gè)actions中也可以這樣寫,actionB處理actionA被觸發(fā)得到的Promise,再提交someOtherMutations
actions:{
   //...
    actionB({diapatch,commit}){
        return dispatch('actionA').then(
            commit('someOtherMutations')  
        )
    }
}
  • 再結(jié)合async await 優(yōu)化組合actions的代碼
actions : {
  async actionA({commit} {
    commit('gotData',await getData())
  }),
  async actionB({dispatch,commit}){
    await dispatch('actionA')  //等待actionA執(zhí)行完成后再執(zhí)行
    commit('gotOtherData', await getOtherData)
  }
}
1.4 getters

getter類似于Vue.js 的computed計(jì)算屬性屁柏,當(dāng)我們需要從state中派生一些狀態(tài)就用getter函數(shù)啦膜,getter函數(shù)的第一個(gè)參數(shù)為state,還可以接受其他參數(shù)有送,而且它的返回值被緩存起來,只有當(dāng)getter依賴值(state中的相關(guān)狀態(tài)值)發(fā)生改變才會(huì)被重新計(jì)算僧家。

  • 基本用法:
getters:{
  doneTodos : {
      return state.todosfilter(todo => todos.count)
  }
}
  • 在頁(yè)面中觸發(fā)getters的兩種方法:
    1. 可以通過this.$store.getters.doneTodos方法可以訪問得到這些派生出來的狀態(tài)值
    2. 還可以使用輔助函數(shù):
    export default{
          computed : {
             //當(dāng)同時(shí)使用多個(gè)getter函數(shù)時(shí)可以這樣寫
              ...mapGetters([
                   'doneTodos',
                   'anotherGetters'
              ])
          }  
    }
    
  • 如果想給一個(gè)getters(doneTodos)再取一個(gè)名字,則使用對(duì)象形式
export default{
      computed : {
          ...mapGetters({
              anotherName: 'doneTodos'
          })
      }  
}
1.5 mudules

當(dāng)store太過于復(fù)雜的時(shí)候?qū)λ囊环N切割雀摘,每一個(gè)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的狀態(tài)
store.state.b // moduleB的狀態(tài)
1.6 mudules局部狀態(tài)
    1. 模塊內(nèi)部mutations 和getters
      對(duì)于模塊內(nèi)部的mutation和getter接受的第一個(gè)參數(shù)就是模塊內(nèi)部局部狀態(tài)對(duì)象
  moduleA = {
    // ...
    state:{count:0},
    mutation : {
        increment(state){
        // 這里的state就是模塊的局部狀態(tài)
            state.count ++
        }
    },
    getters : {
        doubleCount(state){
            // 這里的state就是模塊的局部狀態(tài)
            return state.count * 2
        }
    }
  }
    1. 模塊內(nèi)部actions
      對(duì)于模塊內(nèi)部的actions,模塊內(nèi)部局部狀態(tài)會(huì)通過 context.state方式暴露出來
    moduleA = {
      // ...
        actions : {
          increment({state,context}){
                if(context.state.count % 2 === 1){
                    context.commit('increment')
                }
           }
        }   
    }
    1. 根節(jié)點(diǎn)
      對(duì)于模塊內(nèi)部的getters和actions根節(jié)點(diǎn)的暴露方式:
  moduleA = {
    // ...
    //跟節(jié)點(diǎn)會(huì)通過第三個(gè)參數(shù)暴露出來
    getters : {
        sumWithRootCount(state,context,rootState ){
            return state.count + rooState.count
        }
    },
  //根節(jié)點(diǎn)狀態(tài)會(huì)通過context.rootState暴露出來
    actions : {
      incrementRootSum(state,context,rootState){
          if(context.rootState.count % 2 === 1){
              context.commit('incrementRootSum')
          }
       }
    }
  }
1.7 vuex — 計(jì)算屬性 — 實(shí)現(xiàn)雙向綁定,使用帶有setter的計(jì)算屬性

假設(shè)obj是計(jì)算屬性返回的屬于vuex store中的一個(gè)對(duì)象

<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. 移動(dòng)端多頁(yè)面公用vuex案例

2.1 情景介紹:

當(dāng)前端開發(fā)調(diào)用后端接口獲取數(shù)據(jù)八拱,并在多個(gè)頁(yè)面中展示數(shù)據(jù)時(shí)阵赠,任意組件之間通信,最好的方法就是使用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
    }
})
  • 創(chuàng)建兩個(gè)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>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肌稻,一起剝皮案震驚了整個(gè)濱河市清蚀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌爹谭,老刑警劉巖枷邪,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異诺凡,居然都是意外死亡东揣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門腹泌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嘶卧,“玉大人,你說我怎么就攤上這事凉袱〗嬉鳎” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵专甩,是天一觀的道長(zhǎng)钟鸵。 經(jīng)常有香客問我,道長(zhǎng)涤躲,這世上最難降的妖魔是什么携添? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮篓叶,結(jié)果婚禮上烈掠,老公的妹妹穿的比我還像新娘。我一直安慰自己缸托,他們只是感情好左敌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俐镐,像睡著了一般矫限。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天叼风,我揣著相機(jī)與錄音取董,去河邊找鬼。 笑死无宿,一個(gè)胖子當(dāng)著我的面吹牛茵汰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播孽鸡,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蹂午,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了彬碱?” 一聲冷哼從身側(cè)響起豆胸,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎巷疼,沒想到半個(gè)月后晚胡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嚼沿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年搬泥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伏尼。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖尉尾,靈堂內(nèi)的尸體忽然破棺而出爆阶,到底是詐尸還是另有隱情,我是刑警寧澤沙咏,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布辨图,位于F島的核電站,受9級(jí)特大地震影響肢藐,放射性物質(zhì)發(fā)生泄漏故河。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一吆豹、第九天 我趴在偏房一處隱蔽的房頂上張望鱼的。 院中可真熱鬧,春花似錦痘煤、人聲如沸凑阶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宙橱。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間师郑,已是汗流浹背环葵。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宝冕,地道東北人张遭。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像猬仁,于是被迫代替她去往敵國(guó)和親帝璧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359