Vuex從入門(mén)到實(shí)戰(zhàn)(一)

由于多個(gè)狀態(tài)分散的跨越在許多組件和交互間各個(gè)角落,大型應(yīng)用復(fù)雜度也經(jīng)常逐漸增長(zhǎng)。為了解決這個(gè)問(wèn)題,Vue 提供 vuex:我們有受到 Elm 啟發(fā)的狀態(tài)管理庫(kù)。vuex 甚至集成到 vue-devtools,無(wú)需配置即可訪問(wèn)時(shí)光旅行。

狀態(tài)管理

狀態(tài)的初始化

狀態(tài)管理,我們應(yīng)該并不陌生。

舉個(gè)例子,超市里新進(jìn)了一批商品,管理員給這些商品分類(lèi),建立索引,然后按照順序放入貨架的過(guò)程就是最簡(jiǎn)單的狀態(tài)管理。

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

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

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

簡(jiǎn)單歸類(lèi)后 :

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

這樣,當(dāng)我們需要某一商品時(shí),很容易根據(jù)類(lèi)目檢索到這個(gè)商品 :

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

狀態(tài)的改變

當(dāng)有顧客前來(lái)購(gòu)買(mǎi)商品時(shí),我們需要類(lèi)似的操作來(lái)減少被購(gòu)買(mǎi)商品的數(shù)量 :

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

然而在成千上萬(wàn)的交易量背后,你不知道這些商品被購(gòu)買(mǎi)的詳細(xì)情況,你甚至不知道上周賣(mài)出了多少蘋(píng)果,你也就無(wú)從得知下周該進(jìn)多少。

所以你需要一個(gè)賬目來(lái)記錄商品購(gòu)買(mǎi)明細(xì) :

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

當(dāng)賣(mài)出蘋(píng)果時(shí),POS機(jī)“滴”一聲,記錄生成了 :

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

最簡(jiǎn)單的store

于是,我們得到了一個(gè)最簡(jiǎn)單的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 () { }
  }
}

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

Vue(x) er 須知

開(kāi)始

Vuex 官方文檔:

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

Vuex最核心的概念 :

  1. Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新。
  2. 你不能直接改變 store 中的狀態(tài)。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用。

下面對(duì)此拓展:

對(duì)象引用

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

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))

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

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

提交和分發(fā)

vuex 只是一個(gè)工具,或許過(guò)了這段時(shí)間,過(guò)了這個(gè)項(xiàng)目,你就不會(huì)再用它。

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

不要直接更改狀態(tài), 而是通過(guò)提交(commit)和分發(fā)(dispatch)的方法通知管理者改變對(duì)象狀態(tài),這是大型項(xiàng)目和復(fù)雜狀態(tài)管理的最佳實(shí)踐。

Vuex 核心概念

一個(gè)完整的 Vuex Store

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

const store = new Vuex.Store({
  state: {
    counter: 0
  },
  getters: {
    counter: state => state.counter
  },
  // 可處理異步請(qǐng)求, dispatch 觸發(fā)
  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 觸發(fā)
  mutations: {
    addCounter (state) {
      state.counter ++
    }
  }
})

PS: 仔細(xì)研究一下 dispatch & actions, commit & mutations, 是否有一種似曾相識(shí)的感覺(jué)?

Look, 看這對(duì) emit & on (事件機(jī)制),同樣的事件類(lèi)型,同樣的回調(diào)函數(shù)。

State

單一狀態(tài)樹(shù)

Vuex使用單一狀態(tài)樹(shù),一個(gè)state對(duì)象包含全部應(yīng)用層狀態(tài),使得一個(gè)應(yīng)用只有唯一數(shù)據(jù)源(SSOT, Single Source of Truth)

這對(duì)模塊化并不造成影響

state: {
  moduleA: {

  },
  moduleB: {

  }
}

Getter

state: {
  prop: ''
}

你可以使用store.state.prop直接讀取狀態(tài)的值, 當(dāng)然也可以使用Getter :

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

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

getters: {
  prop = state => state.prop,
  fixedProp = state => state.prop || '暫無(wú)'
}

Mutation

Vuex 中的 mutation 類(lèi)似于事件,有一個(gè)字符串的 事件類(lèi)型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler),回調(diào)函數(shù)的接受state作為第一個(gè)參數(shù),我們?cè)谶@里修改狀態(tài)(state)

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

通過(guò) commit 通知狀態(tài)變化

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

Action

類(lèi)似于mutation,不同在于

  • 只能通過(guò) commit mutation 通知狀態(tài)變化
  • mutation 只能包含同步操作,而 action 可以包含異步操作(比如, 在這里可以執(zhí)行ajax請(qǐng)求)
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)
    })
  }
}

通過(guò) dispatch 通知狀態(tài)變化

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

Module

Vuex 允許我們將store分割成模塊,每個(gè)模塊擁有自己的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 的基本用法已經(jīng)介紹完了。

相關(guān)內(nèi)容 :

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

官方實(shí)例: https://github.com/vuejs/vuex/tree/dev/examples

在下列內(nèi)容中, 我將 演示如何使用 vue + vuex 以及其他常用組件從入門(mén)到實(shí)戰(zhàn)。

Vuex從入門(mén)到實(shí)戰(zhàn)(二)

Vuex從入門(mén)到實(shí)戰(zhàn)(三)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • vuex是一個(gè)狀態(tài)管理模式,通過(guò)用戶的actions觸發(fā)事件,然后通過(guò)mutations去更改數(shù)據(jù)(你也可以說(shuō)狀態(tài)...
    Ming_Hu閱讀 2,135評(píng)論 3 3
  • 安裝 npm npm install vuex --save 在一個(gè)模塊化的打包系統(tǒng)中,您必須顯式地通過(guò)Vue.u...
    蕭玄辭閱讀 3,051評(píng)論 0 7
  • Vuex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)...
    白水螺絲閱讀 4,800評(píng)論 7 61
  • Vuex是什么? Vuex 是一個(gè)專(zhuān)為 Vue.js應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件...
    蕭玄辭閱讀 3,238評(píng)論 0 6
  • Vuex 是什么? ** 官方解釋?zhuān)篤uex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式**。它采用集中...
    Rz______閱讀 2,360評(píng)論 1 10

友情鏈接更多精彩內(nèi)容