Vuex從入門到實戰(一)

由于多個狀態分散的跨越在許多組件和交互間各個角落,大型應用復雜度也經常逐漸增長。為了解決這個問題,Vue 提供 vuex:我們有受到 Elm 啟發的狀態管理庫。vuex 甚至集成到 vue-devtools,無需配置即可訪問時光旅行。

狀態管理

狀態的初始化

狀態管理,我們應該并不陌生。

舉個例子,超市里新進了一批商品,管理員給這些商品分類,建立索引,然后按照順序放入貨架的過程就是最簡單的狀態管理。

let goods1 = {
  category: 'fruit',
  name: 'apple',
  quantity: 5
}

let goods2 = {
  category: 'supplies',
  name: 'toothbrush',
  quantity: 5
}

let goods3 = {
  category: 'clothes',
  name: 'sweater',
  quantity: 5
}

簡單歸類后 :

let shop = {
  goods: {
    fruit: [{ name: 'apple', quantity: 5 }],
    supplies: [{ name: 'toothbrush', quantity: 5 }],
    clothes: [{ name: 'sweater', quantity: 5 }]
  }
}

這樣,當我們需要某一商品時,很容易根據類目檢索到這個商品 :

console.log(shop.goods.fruit.find(f => f.name === 'apple'))
//-> { name: 'apple', quantity: 5 }

狀態的改變

當有顧客前來購買商品時,我們需要類似的操作來減少被購買商品的數量 :

shop.goods.fruit.find(f => f.name === 'apple').quantity --

然而在成千上萬的交易量背后,你不知道這些商品被購買的詳細情況,你甚至不知道上周賣出了多少蘋果,你也就無從得知下周該進多少。

所以你需要一個賬目來記錄商品購買明細 :

let account = {
  appleSold (value) {
    console.log("apple sold " + value)
    shop.goods.fruit.find(f => f.name === 'apple').quantity -= value
  }
}

當賣出蘋果時,POS機“滴”一聲,記錄生成了 :

account.appleSold (5)
//-> apple sold 5

最簡單的store

于是,我們得到了一個最簡單的store :

let shop = {
  goods: {
    fruit: [{ name: 'apple', quantity: 5 }],
    supplies: [{ name: 'toothbrush', quantity: 5 }],
    clothes: [{ name: 'sweater', quantity: 5 }]
  },
  account: {
    appleSold (value) {
      console.log("apple sold " + value)
      shop.goods.fruit.find(f => f.name === 'apple').quantity -= value
    },
    funcN () { }
  }
}

由此可知,狀態管理可以幫助我們更友好的改變狀態,同時,跟蹤狀態變化的軌跡。

Vue(x) er 須知

開始

Vuex 官方文檔:

https://vuex.vuejs.org/zh-cn/getting-started.html

Vuex最核心的概念 :

  1. Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得到高效更新。
  2. 你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地了解我們的應用。

下面對此拓展:

對象引用

下面這兩段代碼將輸出什么? 先不要往下看, 自己寫一下

let store = {
  state: {
    msg: "welcome"
  }
}, copy = store.state;
store.state = {
  hello: "world"
};
console.log(Object.keys(copy));
let store = {
  state: {
    msg: 'welcome'
  }
}, copy = store.state;
store.state.hello = "world";
console.log(Object.keys(copy))

結果如下(如果你都答對了,那么理解和上手Vuex將會很輕松) :

//-> ["msg"]
//-> ["msg", "hello"]

提交和分發

vuex 只是一個工具,或許過了這段時間,過了這個項目,你就不會再用它。

我們要記住的是它留給我們的啟示:

不要直接更改狀態, 而是通過提交(commit)和分發(dispatch)的方法通知管理者改變對象狀態,這是大型項目和復雜狀態管理的最佳實踐。

Vuex 核心概念

一個完整的 Vuex Store

/**
 * index.js
 */
import axios from 'axios'

const store = new Vuex.Store({
  state: {
    counter: 0
  },
  getters: {
    counter: state => state.counter
  },
  // 可處理異步請求, dispatch 觸發
  actions: {
    askPermission ({commit}) {
      axios.get('/url').then((res) => {
        if(res.data.permission)
          commit('addCounter')
      }).catch((err) => {
        console.log('Error: in process "Ask permission".\n Detailed: ' + err)
      })
    }
  },
  // 同步, commit 觸發
  mutations: {
    addCounter (state) {
      state.counter ++
    }
  }
})

PS: 仔細研究一下 dispatch & actions, commit & mutations, 是否有一種似曾相識的感覺?

Look, 看這對 emit & on (事件機制),同樣的事件類型,同樣的回調函數。

State

單一狀態樹

Vuex使用單一狀態樹,一個state對象包含全部應用層狀態,使得一個應用只有唯一數據源(SSOT, Single Source of Truth)

這對模塊化并不造成影響

state: {
  moduleA: {

  },
  moduleB: {

  }
}

Getter

state: {
  prop: ''
}

你可以使用store.state.prop直接讀取狀態的值, 當然也可以使用Getter :

getters: {
  prop = state => state.prop
}

使用Getter的好處在于,你可以從state中派生出一些狀態 :

getters: {
  prop = state => state.prop,
  fixedProp = state => state.prop || '暫無'
}

Mutation

Vuex 中的 mutation 類似于事件,有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler),回調函數的接受state作為第一個參數,我們在這里修改狀態(state)

state: {
  counter: 0
},
mutations: {
  addCounter (state) {
    state.counter ++
  },
  addCounter (state, payload) {
    state.counter += payload.value
  }
}

通過 commit 通知狀態變化

store.commit('addCounter')
store.commit('addCounter', {value: 1})

Action

類似于mutation,不同在于

  • 只能通過 commit mutation 通知狀態變化
  • mutation 只能包含同步操作,而 action 可以包含異步操作(比如, 在這里可以執行ajax請求)
actions: {
  askPermission ({commit}) {
    axios.get('/url').then((res) => {
      if(res.data.permission)
        commit('addCounter')
    }).catch((err) => {
      console.log('Error: in process "Ask permission".\n Detailed: ' + err)
    })
  },
  askPermission ({commit}, payload) {
    axios.get('/url', { params:payload }).then((res) => {
      if(res.data.permission)
        commit('addCounter')
    }).catch((err) => {
      console.log('Error: in process "Ask permission".\n Detailed: ' + err)
    })
  }
}

通過 dispatch 通知狀態變化

store.dispatch('askPermission')
store.dispatch('askPermission', { author: "lonelydawn" })

Module

Vuex 允許我們將store分割成模塊,每個模塊擁有自己的state, mutation, action, getter, 甚至是嵌套子模塊 :

const store = new Vuex.Store({
  modules: {
    a: {
      state: {},
      mutations: {
        addCounter(state) {}
      },
      actions: {},
      getters: {}
    },
    b: {
      namespaced: true, // 建立命名空間
      state: {},
      mutations: {
        addCounter(state) {}
      },
      actions: {}
    }
  }
})

store.state.a
store.state.b

//  提交 給 模塊 a 的 mutations
store.commit('addCounter')
//  提交 給 模塊 b 的 mutations
store.commit('b/addCounter')

最后

Vuex 的基本用法已經介紹完了。

相關內容 :

官方文檔: https://vuex.vuejs.org/zh-cn/

官方實例: https://github.com/vuejs/vuex/tree/dev/examples

在下列內容中, 我將 演示如何使用 vue + vuex 以及其他常用組件從入門到實戰。

Vuex從入門到實戰(二)

Vuex從入門到實戰(三)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • vuex是一個狀態管理模式,通過用戶的actions觸發事件,然后通過mutations去更改數據(你也可以說狀態...
    Ming_Hu閱讀 2,039評論 3 3
  • 安裝 npm npm install vuex --save 在一個模塊化的打包系統中,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,963評論 0 7
  • Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,并以相應...
    白水螺絲閱讀 4,684評論 7 61
  • Vuex是什么? Vuex 是一個專為 Vue.js應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件...
    蕭玄辭閱讀 3,138評論 0 6
  • Vuex 是什么? ** 官方解釋:Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式**。它采用集中...
    Rz______閱讀 2,318評論 1 10