【學習筆記】一文學會使用Vuex

簡介,安裝與初始化

什麼是vuex

VueX是適用於在Vue項目開發時使用的狀態管理工具。Vue爲這些被多個組件頻繁使用的值提供了一個統一管理的工具——VueX。在具備VueXVue項目中,咱們只須要把這些值定義在VueX中,便可在整個Vue項目的組件中使用。javascript

如何安裝vuex

npm安裝vue

npm i vuex -s
複製代碼

如何使用vuex

在項目的根目錄下新增一個store文件夾,在該文件夾內建立index.jsjava

此時項目的src文件夾是這樣的ios

│  App.vue
│  main.js
│
├─assets
│      logo.png
│
├─components
│      HelloWorld.vue
│
├─router
│      index.js
│
└─store
       index.js
複製代碼

在store.js文件中,引入vuex而且使用vuex,這裏注意變量名是大寫Vue和Vuexgit

//store.js
import Vue from 'vue'
import Vuex from 'vuex'
//掛載Vuex
Vue.use(Vuex)
//建立VueX對象
const store = new Vuex.Store({
    state:{
        //存放的鍵值對就是所要管理的狀態
        name:'helloVueX'
    }
})
export default store
複製代碼

將store掛載到當前項目的Vue實例當中去es6

//main.js
import store from './store'
new Vue({
  el: '#app',
  router,
  store,  // 和router同樣,將咱們建立的Vuex實例掛載到這個vue實例中
  render: h => h(App)
})
複製代碼

在組件中使用Vuexgithub

例如在App.vue中,咱們要將state中定義的name拿來在h1標籤中顯示vuex

<template>
    <div id='app'> name: <h1>{{ $store.state.name }}</h1> </div>
</template>
複製代碼

或者要在組件方法中使用npm

methods:{
    add(){
      console.log(this.$store.state.name)
    }
},
複製代碼

具體的使用方法下面會詳細介紹axios

注意:vuex的出現是爲了解決組件間的通訊問題,若是某個操做或者數據不涉及到公共操做,只是單一組件操做,不要把這些狀態值或者function存儲到vuex中,由於vuex會把自身掛載到全部組件上,無論當前組件是否用到裏面的東西,所以這事實上確定增長了性能的損耗的.

VueX中的核心內容

vuex中,有默認的五種基本的對象:

  • state:存儲狀態(變量)
  • getters:對數據獲取以前的再次編譯,能夠理解爲state的計算屬性。
  • mutations:修改狀態,而且是同步的。這個和咱們組件中的自定義事件相似。
  • actions:異步操做。
  • modulesstore的子模塊

拆分紅單文件

若是項目中的狀態和方法過多,index.js文件看起來就會很臃腫而且很差維護,這個時候咱們就能夠把state,getters,mutations,actions拆分紅單個文件,有利於進行管理

此時目錄結構是這樣的

store
│      
│
├─index.js
│      
│      
├─state.js
│      
│
├─getters.js
│      
│
├─mutations.js
│      
│
└─actions.js
複製代碼

index.js

import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
Vue.use(Vuex);
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
});
複製代碼

其餘的文件中只須要export導出便可

state.js

export default {
  name:'hzw'
};
複製代碼

mutations.js

export default {
 changeName(state, name) {
    state.name = name;
  },
};
複製代碼

getters.js

export default {
 realName(state) {
    return "姓名:" + state.name
  },
};
複製代碼

actions.js

export default {
 changeName({ commit }, name) {
        return commit('changeName', name)
    }
};
複製代碼

這樣看起來就更有結構感,也更易於維護了

state以及mapState

什麼是state

state(vuex) ≈ data (vue)

vuexstatevuedata有不少類似之處,都是用於存儲一些數據,或者說狀態值.這些值都將被掛載數據和dom的雙向綁定事件,也就是當值改變的時候能夠觸發dom的更新.

咱們在state.js中聲明一個狀態count,初始值爲0,而後在組件中輸出它

// state.js 
export default {
  count:'0'
};
複製代碼
//組件中
<template>
  <div class="hello"> <h3>{{$store.state.count}}</h3> </div>
</template>
複製代碼

結果以下圖所示

ef5f88b302d72fe35e97717a30fd4627.png

注意:雖然statedata有不少類似之處,但state在使用的時候通常被掛載到子組件的computed計算屬性上,這樣有利於state的值發生改變的時候及時響應給子組件.若是用data去接收$store.state,也是能夠接收到值的,可是因爲這只是一個簡單的賦值操做,因此state中的狀態改變的時候不能被vue中的data監聽到.也能夠經過watch $store去解決這個問題,可是稍微有點麻煩.

因此,最好仍是用computed去接收state,以下,修改state的方法後面會學習,這裏先進行展現.

//mutations.js
export default {
  add(state, n = 0) {
    return (state.count += n)
  },
  reduce(state, n = 0) {
    return (state.count -= n)
  }
}
複製代碼
//組件中
<template>
  <div class="hello"> <h3>{{$store.state.count}}</h3> <div> <button @click="add(10)">增長</button> <button @click="reduce(10)">減小</button> <div>computed:{{dataCount}}</div> <div>data: {{count}}</div> </div> </div>
</template>

<script> export default { name: 'HelloWorld', data () { return { dataCount: this.$store.state.count //用data接收 } }, computed:{ count(){ return this.$store.state.count //用computed接收 } }, methods: { add(n){ this.$store.commit('add',n); }, reduce(n){ this.$store.commit('reduce',n); } } } </script>
複製代碼

而後咱們點擊增長按鈕,看看會發生什麼變化,結果以下

0d5fdacab47043072b5a1ddbbdd9445f.png

能夠看到,用data接收的值不能及時響應更新,用computed就能夠.

知識點:Propsmethods,datacomputed的初始化都是在beforeCreatedcreated之間完成的。

什麼是mapState

表面意思:mapStatestate的輔助函數

實際做用:當一個組件須要獲取多個狀態時候,將這些狀態都聲明爲計算屬性會有些重複和冗餘。爲了解決這個問題,可使用 mapState 輔助函數幫助生成計算屬性

使用方法:先要導入這個輔助函數.

import { mapState } from 'vuex'
複製代碼

而後就能夠在computed中使用mapState

mapState等這種輔助函數的時候,若是組件內部的命名vuex內的命名是一致的,能夠簡寫成數組方式。

//state.js
export default {
    nickname:'Simba',
    age:20,
    gender:'男'
};
複製代碼
//computed
computed: mapState(['nickname','age','gender'])
//上面的一句代碼就至關於下面這些 是否是簡潔了不少
computed:{
  nickname(){return this.$store.state.nickname}
  age(){return this.$store.state.age}
  gender(){return this.$store.state.gender}
}
複製代碼

若是須要自定義一個計算屬性,須要es6中的展開運算符:...

data(){
  return{
    count:14
  }
}
computed: {   
  value(){
   return "姓名:" + this.coount/7
},
  ...mapState(['nickname','age','gender'])
}
複製代碼

getters以及mapGetters

什麼是getters

getters:對數據獲取以前的再次編譯,getters的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。說白了就約等於vuecomputed,能夠像使用computed同樣去使用getters,固然兩者仍是有區別的.

如何使用getters

getters中的方法有兩個默認參數

  • state 當前VueX對象中的狀態對象
  • getters 當前getters對象,用於將getters下的其餘getter拿來用
//state.js
export default {
  name:'simba',
  age:'20'
};
//getters.js
export default {
  // 第一個參數是state
  realName(state) {
    return "姓名:" + state.name
  },
  // 第二個參數能夠訪問getters
  nameAndAge(state, getters) {
    return "年齡:" + state.age +";"+ getters.realName
  }
};
複製代碼

如何訪問getters

經過屬性訪問

getter 會暴露爲 store.getters 對象,咱們能夠以屬性的形式訪問這些值:

store.getters.realName// -> 姓名:simba
複製代碼

注意:getter 在經過屬性訪問時是做爲 Vue 的響應式系統的一部分緩存其中的。

經過方法訪問

咱們能夠經過讓 getters 返回一個函數,來實現給 getters 傳參。這樣在對 store 裏的數組進行查詢時很是有用。

state:{
  todos:[
    {
      id:2,
      text:'…',
      done: false
    }
  ]
},
getters: {
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: ‘…’, done: false }
複製代碼

注意:getter 在經過方法訪問時,每次都會去進行調用,而不會緩存結果。

在組件中使用

咱們在computed中經過this.$store.getters.xxx來綁定一個計算屬性

//組件中
<template>
  <div class="hello"> <div> <div>{{message}}</div> <div>{{message2}}</div> </div> </div>
</template>
computed:{
   message(){
     return this.$store.getters.realName 
   },
   message2(){
     return this.$store.getters.nameAndAge; 
   }
},
複製代碼

結果以下:

236fc2564c76288bdeceedec92efaaaf.png

什麼是mapGetters

mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性:

使用方法:先要導入這個輔助函數.

import { mapGetters } from 'vuex'
複製代碼

而後就能夠在computed中使用mapGetters

computed: {
  ...mapGetters({
    message: "realName",
    message2: "nameAndAge"
  })
},
複製代碼

是否是簡潔了不少,若是計算屬性的名getters的名字相同,還可使用數組簡寫形式

computed: {
  ...mapGetters(["realName","nameAndAge"])
},
複製代碼

mutation以及mapMutation

什麼是mutation

mutation是操做state數據的方法的集合,好比對該數據的修改、增長、刪除等等。mutation中一般存放一些同步修改狀態的方法.

注意:更改 Vuexstore 中的狀態的惟一方法是提交 mutation

如何使用mutation

mutations方法都有默認的形參:mutation([state] [,payload])

  • state 當前VueX對象中的state
  • payload 載荷(該方法在被調用時傳遞的參數)
//state.js
export default {
  name:'韓志偉'
};
//mutations.js
export default {
 changeName(state, name) {
    state.name = name;
  },
};
複製代碼

咱們須要這樣去調用mutation

this.$store.commit('changeName','吳彥祖')
複製代碼

例如咱們在組件的methods中修改一下name屬性

methods: {
    changeName(name){
      this.$store.commit('changeName',name);
    },
}
//調用changeName方法
mounted(){
  this.changeName('吳彥祖')
}
複製代碼

當須要多參提交時,能夠把他們放在一個對象中

this.$store.commit('changeName',{firstName:'han',lastName:'zhiwei'})
複製代碼

也能夠用另一種傳參的方式

this.$store.commit({
    type:'changeName',
    payload:{
        firstName:'han',
        lastName:'zhiwei'
    }
})
複製代碼

什麼是mapMutation

mapMutation輔助函數僅僅是將 store 中的 mutation 映射到組件methods

使用方法:先要導入這個輔助函數.

import { mapMutation} from 'vuex'
複製代碼

而後就能夠在methods中使用mapMutation

methods:{
 ...mapMutations({
      changeName:'changeName',
    })
}
複製代碼

這個代碼等同於下面這段

changeName(payLoad){
  this.$store.commit('changeName',payLoad)
}
複製代碼

若是方法名mutation名字同樣 能夠簡寫成下面這樣

methods:{
 ...mapMutations(['changeName'])
}
複製代碼

還可使用常量替代mutations事件類型

store文件夾下面新建mutation-types.js文件

//mutation-types.js
export const ADD_AGE = 'ADD_AGE'
//mutations.js
import * as types from './mutation-types';
export default {
  [types.ADD_AGE](state, payLoad) {
    state.age += payLoad.number
  }
}
//組件中js部分
 ...mapMutations([types.ADD_AGE]),
複製代碼

可是這個不是很經常使用,知道有這個知識點就能夠了

增刪state中的成員

既然講到了如何修改state的值,順便提一下如何增刪state中的成員

Vue.set 爲某個對象設置成員的值,若不存在則新增

Vue.set(state,"age",22)
複製代碼

Vue.delete 刪除成員

Vue.delete(state,'age')
複製代碼

actions以及mapActions

什麼是actions

因爲直接在mutation方法中進行異步操做,可能會引發數據失效。因此提供了Actions來專門進行異步操做,相似於axios請求,最終經過提交mutation方法來修改state中的值。

如何使用actions

Actions中的方法有兩個默認參數: Action([context ] [,payload])

  • context 上下文對象 包含dispatch commit state getters rootState 可使用es6的解構賦值看起來更明確{ commit }
  • payload 載荷(該方法在被調用時傳遞的參數)

看一個例子,一秒鐘之後提交mutation修改state中的name屬性

//state.js
export default {
  name:'韓志偉'
};
//mutations.js
export default {
 changeName(state, name) {
    state.name = name;
  },
};  
//actions.js
export default {
 asyncChangeName({ commit } ,name) {
   setTimeout(() => {
     commit('changeName',name);
  }, 1000);
  },
};
複製代碼

咱們須要這樣去調用action

this.$store.dispatch('asyncChangeName','吳彥祖')
複製代碼

例如咱們在組件的methods中修改一下name屬性

methods: {
    changeName(name){
      this.$store.dispatch('asyncChangeName',name);
    },
}
//調用changeName方法
mounted(){
  this.changeName('吳彥祖')
}
複製代碼

action中也能夠調用另外一個action

//actions.js
export default {
 asyncChangeName({ dispatch }) {
   setTimeout(() => {
     dispatch('anotherAction');
  }, 1000);
  },
 anotherAction(){
   console.log('另外一個action被調用了')
 }
};
複製代碼

action中也能夠傳入state,以及rootState,至於什麼是rootState,下面學習模塊化modules的時候就知道了

//actions.js
export default {
 action({ state }) {
   setTimeout(() => {
      console.log(state.name)
  }, 1000);
  },
 anotherAction({ rootState }){
   setTimeout(() => {
     console.log(rootState.name);
  }, 1000);
 }
};
複製代碼

至於actions的傳參就與mutation同樣了

this.$store.dispatch('changeName',{firstName:'han',lastName:'zhiwei'})
複製代碼

什麼是mapActions

mapActions輔助函數僅僅是將 store 中的 actions 映射到組件methods

使用方法:先要導入這個輔助函數.

import { mapActions} from 'vuex'
複製代碼

而後就能夠在methods中使用mapActions

methods:{
 ...mapActions({
      changeName:'changeName',
    })
}
複製代碼

這個代碼等同於下面這段

changeName(payLoad){
  this.$store.dispatch('changeName',payLoad)
}
複製代碼

若是方法名actions名字同樣 能夠簡寫成下面這樣

methods:{
 ...mapActions(['changeName'])
}
複製代碼

modules模塊化

什麼是modules

當項目龐大,狀態很是多時,能夠採用模塊化管理模式Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 statemutationactiongetter

初始化modules

前面咱們學習瞭如何將vuexindex.js文件拆分紅單個文件進行管理,因此咱們依然對全部的模塊進行單文件拆分管理,目錄結構以下

store
│      
├─index.js
│            
├─state.js
│      
├─getters.js     
│
├─mutations.js      
│
├─actions.js        
│
└─modules
      │
      ├─moduleA // moduleA的結構與moduleB相同
      │
      └─moduleB
            │ 
            ├─index.js
            │            
            ├─state.js
            │      
            ├─getters.js     
            │
            ├─mutations.js      
            │
            └─actions.js
複製代碼

1.首先根index.js中除了引入自身的state,getters,mutations,actions以外,還要引入兩個模塊的index.js並在export中導出modules

import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
import moduleA  from './modules/moduleA/index';
import moduleB  from './modules/moduleB/index';
Vue.use(Vuex);
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters,
  modules: {
    moduleA,
    moduleB,
  },
});
複製代碼

2.在 moduleA 的index.js中導入moduleA的state,getters,mutations,actions. moduleB同理

注意:gettermutationaction 他們默認都是註冊在全局命名空間的,因此咱們默認是能夠和使用根狀態同樣去使用他們,這樣就失去了模塊化的意義,因此咱們要在模塊的index.js中添加namespaced: true使其成爲帶命名空間的模塊。當模塊被註冊後,它的全部 getteractionmutation 都會自動根據模塊註冊的路徑調整命名。

import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
const moduleA = {
  namespaced: true,
  state: state,
  getters: getters,
  mutations: mutations,
  actions: actions,
};
export default moduleA ;
複製代碼

3.moduleA下的state,getters,mutations,actions就和以前學習的同樣導出就能夠了

//state.js
export default {
  name:'hzw'
};
//mutations.js
export default {
 changeName(state, name) {
    state.name = name;
  },
};  
//以此類推
複製代碼

如何在模塊化中進行定義

state

正常寫在各自的state.js中便可

getter

getter的話,他會有三個參數,第一個是模塊內的 state,第二個是 模塊內的 getters,第三個是根節點狀態 rootState

//getters.js
export default {
  nameAndAge(state, getters, rootState) {
    return "年齡:" + state.age +";"+ getters.realName + "" + rootState.name
  }
};
複製代碼

mutation

mutation 傳入的第一個參數也是模塊內的 state,其實就和根狀態定義 mutation 的時候同樣

export default {
//這裏的state是模塊的局部狀態
 changeName(state, name) {
    state.name = name;
  },
};
複製代碼

actions

action 的話,他傳入仍是隻有 context 對象,這個對象裏面的 state 屬性指模塊內的狀態,rootState 指根狀態,以下

export default {
 changeName({ state,rootState }) {
        console.log(state.name)
        console.log(rootState .name)
    }
};
複製代碼

如何在模塊化中進行開發

1. state 獲取

這個要在原來狀態名前面加一個模塊名才能取到到模塊內的對象。

this.$store.state.moduleA.name;
複製代碼

輔助函數也同樣,name 前面加個模塊名

...mapState({     
  name: state => state.moduleA.name, 
})
//簡寫
...mapState('moduleA',['name']),
複製代碼

獲取根節點的狀態仍是和之前同樣,不須要加模塊名,也不須要加root

...mapState(['name']),
複製代碼

2. getters獲取

這個一樣要在原來狀態名前面加一個模塊名才能取到到模塊內的對象。

在獲取根狀態下的getters不須要加模塊名

store.getters.moduleA.realName
//map函數的第一個參數也一樣須要加模塊名
computed: {
  //獲取moduleA下的getters
  ...mapGetters("moduleA",["realName","nameAndAge"])
  //獲取根狀態下的getters
  ...mapGetters(["realName"])
},
複製代碼

3.調用mutation以及action

根據stategetters推算,在調用模塊內mutationaction的時候確定也須要加模塊名

在調用根狀態中的mutationaction的時候不須要加模塊名

methods:{
//調用模塊A下的action
 ...mapActions('moduleA',['changeName'])
//調用模塊A下的mutation
 ...mapMutation('moduleB',['changeName'])
//調用根狀態下的action
 ...mapActions(['changeName'])
//調用根狀態下的mutation
 ...mapMutation(['changeName'])
}
複製代碼

4.須要特別注意的是,在模塊中的action下調用根狀態中的action和mutation須要將{root:true}做爲第三個參數傳入

//moduleA下的actions.js
export default {
 AsyncChangeName({ commit } ,name) {
   setTimeout(() => {
     //調用的是根狀態下的mutation
     commit('changeName',name,{ root: true });
     //調用的是根狀態下的action
    dispatch('changeName',name,{ root: true });
    }, 1000);
  },
};
複製代碼

5.將模塊中的action註冊爲全局

這個感受和模塊化的設計有點衝突,而且也不經常使用,知道有這個知識點便可,在聲明action的時候,添加root:true並將 action 的定義放到 hanler 函數中,具體以下:

//actions.js
export default {
 globalAction:{
  root:true,
  handler({ commit } ,name) {
   setTimeout(() => {
     commit('changeName',name);
   }, 1000);
  },
 }
};

複製代碼

到這裏就徹底可使用vuex進行開發任務了!

打個廣告

16.gif 這是我一個開源的收藏網址的項目

項目地址👉👉點擊進入,能夠直接設置爲瀏覽器主頁或者桌面快捷方式進行使用,本人在用,長期維護。

徹底開源,你們能夠隨意研究,二次開發。固然仍是十分歡迎你們點個Star⭐⭐⭐
👉👉源碼連接(gitee)       👉👉源碼連接(github)

連接整合

🔊項目預覽地址(GitHub Pages):👉👉alanhzw.github.io

🔊項目預覽備用地址(本身的服務器):👉👉warbler.duwanyu.com

🔊源碼地址(gitee):👉👉gitee.com/hzw_0174/wa…

🔊源碼地址(github):👉👉github.com/alanhzw/War…

🔊個人博客:👉👉www.duwanyu.com

相關文章
相關標籤/搜索