Vuex Demo 入門解析

Vuex的做用

  • Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化
  • 使用Vuex後組件仍然保有局部狀態,使用 Vuex 並不意味着你須要將全部的狀態放入 Vuex。雖然將全部的狀態放到 Vuex 會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。若是有些狀態嚴格屬於單個組件,最好仍是做爲組件的局部狀態。你應該根據你的應用開發須要進行權衡和肯定。

Vuex基本結構

  • state 用來數據共享數據存儲
  • mutation 用來註冊改變數據狀態
  • getters 用來對共享數據進行過濾操做
  • action 解決異步改變共享數據
//src/store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //變量data
  state: {},
  //相似於計算屬性computed
  getters: {},
  //方法methods
  mutations: {},
  //異步操做
  actions: {},
  //模塊
  modules: {}
});
複製代碼
//src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

Vue.config.productionTip = false

new Vue({
  router,
  // 把 store 對象提供給 「store」 選項,這能夠把 store 的實例注入全部的子組件
  store,
  render: h => h(App)
}).$mount('#app')

複製代碼

State

Vuex 使用單一狀態樹,即用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。這也意味着,每一個應用將僅僅包含一個 store 實例。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。vue

//src/store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //變量data
  state: {
    count: 100,
  },
  //方法methods
  mutations: {},
  //異步操做
  actions: {},
  //模塊
  modules: {},
  //相似於計算屬性computed
  getters: {}
});
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="home">
	<!--在此使用$store.state.count使用以前聲明的count-->
    count:{{ $store.state.count }}
    <br>
    <!--在此經過計算屬性doubleCount獲得count-->
    doubleCount:{{doubleCount}}
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: "Home",
  computed: {
    doubleCount(){
      return this.$store.state.count * 2
    }
  },
  components: {},
};
</script>
複製代碼

在devtool中能夠查看到在state聲明的count vuex

1.png

Getter

Vuex 容許咱們在 store 中定義「getter」(能夠認爲是 store 的計算屬性),getter相似於計算屬性, 其返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算緩存

Getter 接受 state 做爲其第一個參數

//src/store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //變量data
  state: {
    count: 100,
    people:[
      {name:'小A', age:8, address:'北京'},
      {name:'小B', age:18, address:'上海'},
      {name:'小C', age:28, address:'廣州'}
    ]
  },
  //相似於計算屬性computed
  getters: {
    getPeople:state=>{
      return state.people.filter(n=>n.age>10)
    }
  },
  //方法methods
  mutations: {},
  //異步操做
  actions: {},
  //模塊
  modules: {}
});
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="about">
    <h1>{{$store.getters.getPeople}}</h1>
  </div>
</template>
複製代碼

2.png

Getter 也能夠接受其餘 getter 做爲第二個參數

//src/store/index.js
  getters: {
    getPeople:state=>{
      return state.people.filter(n=>n.age>10)
    },
    getPeopleLength:(state,getters)=>{
      //直接調用上面的getPeople方法並取得其長度
      return getters.getPeople.length
    }
  }
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="about">
    <h1>getPeople:{{$store.getters.getPeople}}</h1>
    <h3>getPeopleLength:{{$store.getters.getPeopleLength}}</h3>
  </div>
</template>
複製代碼

3.png

經過讓 getter 返回一個函數,來實現給 getter 傳參

//src/store/index.js
getters: {
    getPeople: (state) => {
      return state.people.filter((n) => n.age > 10);
    },
    getPeopleLength: (state, getters) => {
      //直接調用上面的getPeople方法並取得其長度
      return getters.getPeople.length;
    },
    getPeopleByage: (state) => (age) => {
      return state.people.find((n) => n.age === age);
    },
    /*等同於
    getPeopleByage:function(state){
      return function(age){
        return state.people.find(function(n){
          return n.age===age
        })
      }
    }*/
  }
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="about">
    <h1>getPeople:{{$store.getters.getPeople}}</h1>
    <h3>getPeopleLength:{{$store.getters.getPeopleLength}}</h3>
    <h5>getPeopleByage:{{$store.getters.getPeopleByage(28)}}</h5>
  </div>
</template>
複製代碼

4.png

Mutation

更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的事件類型 (type) 和 一個回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數bash

雖然直接對state進行更改也能夠獲得一樣的效果,可是devtool沒法監聽到state的變化,這將會給項目的維護帶來困難,因此對狀態更改仍是須要使用commit方法app

//src/store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //變量data
  state: {
    count: 100,
    people: [
      { name: "小A", age: 8, address: "北京" },
      { name: "小B", age: 18, address: "上海" },
      { name: "小C", age: 28, address: "廣州" },
    ],
  },
  //相似於計算屬性computed
  getters: {
    getPeople: (state) => {
      return state.people.filter((n) => n.age > 10);
    },
    getPeopleLength: (state, getters) => {
      //直接調用上面的getPeople方法並取得其長度
      return getters.getPeople.length;
    },
    getPeopleByage: (state) => (age) => {
      return state.people.find((n) => n.age === age);
    },
  },
  //方法methods
  mutations: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    }
  },
  //異步操做
  actions: {},
  //模塊
  modules: {},
});
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="home">
    count:{{ $store.state.count }}
    <br />
    doubleCount:{{ doubleCount }}
    <button @click="add">+</button>
    <button @click="sub">-</button>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: "Home",
  computed: {
    doubleCount() {
      return this.$store.state.count * 2;
    }
  },
  methods: {
    add(){
      this.$store.commit('increment')
    },
    sub(){
      this.$store.commit('decrement')
    }
  },
  components: {},
};
</script>
複製代碼

5.png

你能夠向 store.commit 傳入額外的參數,即 mutation 的 載荷(payload)異步

//src/store/index.js
mutations: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    },
    mul(state,payload){
      state.count *= payload.amount
    }
  }
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="home">
    count:{{ $store.state.count }}
    <br />
    doubleCount:{{ doubleCount }}
    <button @click="add">+</button>
    <button @click="sub">-</button>
    <button @click="mul">*10</button>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: "Home",
  computed: {
    doubleCount() {
      return this.$store.state.count * 2;
    },
  },
  methods: {
    add() {
      this.$store.commit("increment");
    },
    sub() {
      this.$store.commit("decrement");
    },
    mul() {
      this.$store.commit({
        type: "mul",
        amount: 10,
      });
    },
  },
  components: {},
};
</script>
複製代碼

6.png

Action

Action 相似於 mutation,不一樣在於:函數

  • Action 提交的是 mutation,而不是直接變動狀態
  • Action 能夠包含任意異步操做

理解了mutation以後理解action也相對簡單,action用於處理異步操做,與mutation相比,action經過$store.dispatch('xxx')觸發而不是store.commit('xxx'),觸發以後會交給對應的action處理異步操做,而後再經過commit交予mutation實現數據更改。流程可簡單理解爲`store.dispatch => action => $store.commit => mutation`學習

<!--src/views/Home.vue-->
<template>
  <div class="home">
    count:{{ $store.state.count }}
    <br />
    doubleCount:{{ doubleCount }}
    <button @click="add">+</button>
    <button @click="sub">-</button>
    <button @click="mul">*10</button>
    <button @click="div">/10</button>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: "Home",
  computed: {
    doubleCount() {
      return this.$store.state.count * 2;
    },
  },
  methods: {
    add() {
      this.$store.commit("increment");
    },
    sub() {
      this.$store.commit("decrement");
    },
    mul() {
      this.$store.commit({
        type: "mul",
        amount: 10,
      });
    },
    div() {
      this.$store.dispatch("division");
    },
  },
  components: {},
};
</script>
複製代碼
//src/store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  //變量data
  state: {
    count: 100,
    people: [
      { name: "小A", age: 8, address: "北京" },
      { name: "小B", age: 18, address: "上海" },
      { name: "小C", age: 28, address: "廣州" },
    ],
  },
  //相似於計算屬性computed
  getters: {
    getPeople: (state) => {
      return state.people.filter((n) => n.age > 10);
    },
    getPeopleLength: (state, getters) => {
      //直接調用上面的getPeople方法並取得其長度
      return getters.getPeople.length;
    },
    getPeopleByage: (state) => (age) => {
      return state.people.find((n) => n.age === age);
    },
  },
  //方法methods
  mutations: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    },
    mul(state, payload) {
      state.count *= payload.amount;
    },
    div(state, payload) {
      state.count /= payload.amount;
    },
  },
  //異步操做
  actions: {
    division(context) {
      context.commit({
        type: "div",
        amount: 10,
      });
    },
  },
  //模塊
  modules: {},
});
複製代碼

7.png

Module

因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。 爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊. 要調用定義的模塊內的屬性可以使用$store.state.模塊.屬性ui

//src/store/index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const moduleA = {
  state: {
    count: 11111111111111,
  },
  mutations: {},
  actions: {},
  getters: {
    //對於模塊內部的 getter,根節點狀態會做爲第三個參數暴露出來
    sumWithRootCount(state, getters, rootState) {
      return state.count + rootState.count;
    }
  }
};

export default new Vuex.Store({
  //變量data
  state: {
    count: 100,
    people: [
      { name: "小A", age: 8, address: "北京" },
      { name: "小B", age: 18, address: "上海" },
      { name: "小C", age: 28, address: "廣州" },
    ],
  },
  //相似於計算屬性computed
  getters: {
    getPeople: (state) => {
      return state.people.filter((n) => n.age > 10);
    },
    getPeopleLength: (state, getters) => {
      //直接調用上面的getPeople方法並取得其長度
      return getters.getPeople.length;
    },
    getPeopleByage: (state) => (age) => {
      return state.people.find((n) => n.age === age);
    },
  },
  //方法methods
  mutations: {
    increment(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    },
    mul(state, payload) {
      state.count *= payload.amount;
    },
    div(state, payload) {
      state.count /= payload.amount;
    },
  },
  //異步操做
  actions: {
    division(context) {
      context.commit({
        type: "div",
        amount: 10,
      });
    },
  },
  //模塊
  modules: {
    moduleA
  },
})
複製代碼
<!--src/views/Home.vue-->
<template>
  <div class="home">
    count:{{ $store.state.count }}
    <br/>
    doubleCount:{{ doubleCount }}
    <button @click="add">+</button>
    <button @click="sub">-</button>
    <button @click="mul">*10</button>
    <button @click="div">/10</button>
    <br>
    {{$store.state.moduleA.count}}
    {{$store.state.sumWithRootCount}}
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: "Home",
  computed: {
    doubleCount() {
      return this.$store.state.count * 2;
    }
  },
  methods: {
    add() {
      this.$store.commit("increment");
    },
    sub() {
      this.$store.commit("decrement");
    },
    mul() {
      this.$store.commit({
        type: "mul",
        amount: 10,
      });
    },
    div() {
      this.$store.dispatch("division");
    },
  },
  components: {},
};
</script>
複製代碼

8.png

關於Vuex還有一些功能未講述,可進入Vuex官網繼續學習this

相關文章
相關標籤/搜索