vue的狀態管理模式—vuex

lizhen06發表於2018-10-19

前言

如果你在使用Vue.js,肯定有很多元件之間相互傳遞引數的經歷。當遇到父子元件需要通訊的時候,我們經常用的方法是傳遞引數。其實除了傳遞引數的方式,我們還可以結合業務需要考慮是否用Vuex去解決。

Vuex是什麼?

官方文件的定義:Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

狀態管理模式集中式儲存管理初次瞭解的話感覺有點難以理解,我們通過官方文件中提供的這張圖加深下理解。

vue的狀態管理模式—vuex
Vuex是一種設計思想。每一個Vuex應用的核心就是Store(倉庫)。元件的狀態和資料都放到一個統一的記憶體空間state去管理,state的資料對映到元件上,當元件的資料發生變化時,通過Dispatch Actions或者直接Commit Mutations的方法修改state。我們不能直接改變state中的狀態。改變state中狀態的唯一途徑就是顯式的提交(Commit)Mutations。這樣使得我們可以方便的追蹤每一個狀態的變化,從而使我們能夠實現一些功能幫助我們更好的瞭解我們的應用。state修改後反映到元件上,形成閉環。

當以往父子元件通訊的時候,我們通常會採用props+emit的方式。vuex適合更為複雜的使用場景。比如:

  • 解決多個關聯度比較低的兄弟元件之間的狀態共享
  • 解決路由間跳轉複雜的引數傳遞

實際應用

小編最近在做一個專案的填寫釋出頁面的功能,簡化來說就是從first頁面填寫資訊後,點選跳轉到second頁面,同時傳入first頁面中填寫的資訊。那麼如何用Vuex的方式實現呢?

vue的狀態管理模式—vuex
首先我們需要在開發環境中安裝Vuex:

npm install vuex --save
複製程式碼

然後在專案的src目錄下增加store資料夾,目錄如下

vue的狀態管理模式—vuex
其中:

  • index.js:入口檔案
  • state.js:儲存狀態。也就是變數。
  • getters.js:派生狀態。也可以理解為set、get中的get。有兩個可選引數,state、getters分別可以獲取state中的變數和其它getters。和vue中的computed類似。
  • mutations.js:提交狀態修改。可以理解為set、get中的set。每一個mutation都有一個字串的事件型別和回撥函式。第一個引數預設為state。vuex中唯一修改state的方式,不支援非同步操作。和vue中的methods類似。
  • mutation-types.js:儲存於mutations相關的字串常量,方便檢測和管理。
  • actions.js:和mutations類似。支援非同步操作,也可以是對mutations的封裝。

state.js 示例:

const state = {
    userInfo: {}
};
export default state;
複製程式碼

userinfo 存放我們需要提交的資訊

mutation-types.js 示例:

export const SET_USERINFO = 'SET_USERINFO';
複製程式碼

mutation.js 示例:

import * as types from './mutation-types'

const mutations = {
    [types.SET_USERINFO](state, userInfo) {
        state.userInfo = userInfo;
    }
}
複製程式碼

是一個物件,裡面存放一些方法,方法名就是mutation-types裡存放的常量名,第一個引數對應的是state.js檔案中的state;第二個引數是提交的引數。

getters.js 示例:

export const userInfo = state => state.userInfo;
複製程式碼

獲取state的狀態到元件。

index.js入口檔案配置,元件Vuex示例:

import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as getters from './getters'
import state from './state'
import mutations from './mutations'

import createLogger from 'vuex/dist/logger'

Vue.use(Vuex)

// 開發環境為true,生產環境為false
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
    actions,
    getters,
    state,
    mutations,
    plugin: debug ? [createLogger()] : []
})

複製程式碼

最後再將store例項注入main.js裡的vue例項中:

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
new Vue({
    el: '#app',
    router,
    store,
    render: h => h(App)
})
複製程式碼

完成這些基本的配置之後,接下來我們就要到專案中的呼叫了。Vuex為我們提供了一系列的語法糖:mapMutations,mapGetters,mapActions,省去了繁瑣的操作。我們可以直接按照vue呼叫methods和computed的方式去呼叫。

首先我們看下第一步first.vue的部分: template:

<template>
  <div class="page">
    <div>姓名: <input type="text" v-model="name"></div>
    <div>年齡: <input type="text" v-model="age"></div>
    <div>
      <button @click="jumpToNextPage">下一頁</button>
    </div>
  </div>
</template>
複製程式碼

script:

import { mapMutations, mapActions } from "vuex";
export default {
  data() {
    return {
      name: '張三',
      age: '20',
      personInfo: {}
    };
  },
  methods: {
    jumpToNextPage() {
      this.personInfo.name = this.name;
      this.personInfo.age = this.age;
      this.$router.push({
        path: `/second/`
      });
      this.setInfo(this.personInfo);
    },
    ...mapMutations({
      setInfo: 'SET_USERINFO'
    })
  }
};
複製程式碼

我們在這一步獲取使用者填寫的資訊提交到mutations。

首先我們需要從vuex引入mapMutations去操作state的變化。根據文件提供的方法,在methods裡通過擴充套件運算子的方式呼叫。我們在mapMutations裡需要做一個對映,setInfo對應的是mutation-types裡的常量SET_USERINFO。然後在點選跳轉到下一頁按鈕的時候執行this.setUser()這個方法,並且傳入資訊引數。

修改mutations之後,接下來就是在第二頁獲取state的變化了。

接下來我們來看second.vue的部分:template:

<template>
    <div class="page">
      姓名:{{userInfo.name}}
      年齡:{{userInfo.age}}
    </div>
</template>
複製程式碼

script:

import { mapGetters } from "vuex";
export default {
  data() {
    return {
    };
  },
  computed: {
    ...mapGetters(["userInfo"])
  },
  created() {
    console.log(this.userInfo);
  },
  methods: {
  }
};
複製程式碼

第一步我們同樣需要從vuex中引入mapGetter。然後在computed中,同樣按照擴充套件運算子的方式引入需要得到的資料。此處userInfo對應的是getter.js中定義的userInfo。

這樣我們就通過vuex完成了從修改提交資料到獲取資料的整個過程。

剛才的部分我們是直接提交mutations,現在我們再來看下如何通過actions來提交mutations的變化。

actions.js 示例:

import * as types from './mutation-types';

export const actionsSetUserInfo = function ({ commit, state }, userInfo) {
  commit(types.SET_USERINFO, userInfo);
}
複製程式碼

引入mutation-types之後,定義提交mutation的函式,actionSetUserInfo。commit和state是預設引數,userInfo是修改的引數資料。

此時first.vue修改為:

import { mapMutations, mapActions } from "vuex";
export default {
  data() {
    return {
      name: '張三',
      age: '20',
      personInfo: {}
    };
  },
  methods: {
    jumpToNextPage() {
      this.personInfo.name = this.name;
      this.personInfo.age = this.age;
      this.$router.push({
        path: `/second/`
      });
      this.actionsSetUserInfo(this.personInfo);
    },
    ...mapActions([
      'actionsSetUserInfo'
    ])
  }
};
複製程式碼

這樣,actions.js 裡actionSetUserInfo就被執行。通過commit mutation修改state中的使用者資訊。

結束語

簡單理解Vuex就是把元件之間需要共享的變數,全部儲存到一個物件裡,然後這個物件放在頂層元件中供其他元件使用。只不過我們需要按照Vvuex指定的規則對這些資料的存和取。

初次發文,僅是個人的一些理解,歡迎留言批評指正。

相關文章