在Vue項目中使用Vuex
什麼是Vuex
“Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。”
那什麼是狀態呢?以我的理解就是在vue組件的data中的屬性需要共享給其他vue組件使用的部分,就叫做狀態。簡單的說就是data中需要共用的屬性。所以Vuex可以這麼理解:集中管理所有組件中需要共用的屬性(數據),並且規定了對這些屬性的操作。每次對這些屬性進行操作都要遵守規定的形式,這樣可以保證這些屬性“以一種可預測的方式發生變化”。
關於Vuex的詳細介紹可以直接移步官方文檔:https://vuex.vuejs.org/zh-cn/。本文的內容主要是在實際項目中使用Vuex。
Vuex組成
Vuex的主要概念如下:
- Store
表示對Vuex對象的全局引用。組件通過Store來訪問Vuex對象中的State(下面講到) - State
Vuex對象的狀態,即其所擁有的數據 - Getter
相當於Store的計算屬性。因爲就像計算屬性一樣,Getter的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被重新計算。下面會說到具體的使用場景 - Mutation
定義了對State中數據的修改操作。組件使用State中的數據的時候並不能直接對數據進行修改操作,需要調用Mutation定義的操作來實現對數據的修改。這也是Vuex定義中所說的用相應的規則來讓數據發生變化的具體實現 - Action
Mutation中定義的操作只能執行同步操作,Vuex中的異步操作在Action中進行,Action最終通過調用Mutation的操作來更新數據 - Module
Store和State之間的一層,便於大型項目管理,Store包含多個Module,Module包含State、Mutation和Action
使用Vuex
安裝Vuex
當我們想在一個vue項目中使用Vuex的話,首先需要先安裝Vuex依賴。可以直接利用npm安裝:
npm install vuex --save
//加上 --save 表示的是這個依賴在部署之後仍需要
Store、State和Mutation
在項目的源代碼文件夾下(如src文件夾)新建一個store文件夾(叫別的名字也行)。store文件夾下新建一個store.js文件,用來存放Vuex實例。
假設我們的項目是一個閱讀類的應用,需要維護一個叫做books的表示書籍對象的數組。應用可以做的操作是添加新書籍,則其最基本的store.js文件的內容如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
books: [],
},
mutations: {
//所有mutations中的方法的第一個參數一定是state變量,用來進行對state中的狀態的操作
//第二個參數是可選參數,用於調用該 mutations 方法的時候傳參
initBooks (state, books) {
state.books = books
},
addNewBook (state, book) {
state.books.unshift(book)
}
}
})
export default store
使用的場景如下:
在需要使用store中的共有變量的組件中(如newbook.vue),先import store對象。獲得store對象的引用,以便後續對其進行操作。
import store from '@/store/store'
然後在組件的methods中使用store實例的commit屬性來進行一個對Store的state中的數據的操作(如增加、減少等):
methods: {
onSubmit: function() {
this.form.id = index++
store.commit('addNewBook', this.form)
}
}
只能通過提交commit的方式來更新數據會讓人覺得束手束腳甚至多此一舉。因爲直接在組件中修改數據不是更方便嗎?提交commit的方式只不過把應該寫在組件中的操作代碼寫到了store文件中?那爲什麼Vuex還這樣規定呢?因爲Vuex的目的是“以相應的規則保證狀態以一種可預測的方式發生變化”。組件只能通過提交Mutation中規定的方法對數據進行操作,保證了狀態變化的可預測性。如果說允許組件原地對state中的狀態進行更改操作,那狀態的變化方式難免千奇百怪,並且難以跟蹤數據到底在哪裏發生了變化、發生了什麼變化。
這樣子,本來應該在newbook.vue中維護的books數組(或者是在其父組件中維護的books數組,這裏只是舉個例子)被放在Store中維護。並且每一個需要books數組的組件都要從Store中獲取,每一次對books數組進行操作都要提交commit。mutations中的方法相當於提供了一個更改Store中狀態的接口。有了Vuex,我們終於可以擺脫一層層傳遞信息的麻煩和混亂。
前面說到了store、mutation、state的基本使用場景,下面說一下剩下的。
Action
mutation中只能進行同步操作,那如果需要用到異步操作該怎麼辦呢?如上面的例子,閱讀類的應用,假設應用啓動的時候需要從服務器獲取到在數據庫中的所有書籍的信息,這個操作相對於其他基本操作來說會比較耗時,爲了保證應用的流暢性,應該選擇異步獲取書籍數據。因爲這個操作要更新books數組,需要用提交的方式通知Vuex更新數據,但是mutation只能進行同步操作。Vuex提供了進行異步操作的方式,即Action。在Action中定義操作的形式與在mutation中差不多,區別是Action中的操作都是異步操作,且它不能直接修改state中的狀態,對於狀態的修改最終還是要通過提交commit的方式修改。增加了Action之後的store.js文件如下:
import Vue from 'vue'
import Vuex from 'vuex'
// 使用axios作爲http服務模塊
import axios from 'axios'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
books: [],
},
mutations: {
//所有mutations中的方法的第一個參數一定是state變量,用來進行對state中的狀態的操作
//第二個參數是可選參數,用於調用該 mutations 方法的時候傳參
initBooks (state, books) {
state.books = books
},
addNewBook (state, book) {
state.books.unshift(book)
}
},
actions: {
//{ commit }是參數解構的寫法,詳見ES6語法
fetchData ({ commit }) {
axios.get('http://127.0.0.1:8081/api/books')
.then(function (response) {
commit('initBooks', response.data)
})
.catch(function (error) {
console.log(error)
})
},
//book是調用該操作時傳過來的附加參數
addItem ({ commit }, book) {
return axios.post('http://127.0.0.1:8081/api/add', book)
.then(function (response) {
if (!response || response.status !== 200 || response.data.err) {
return true
} else {
commit('addNewBook', book)
return false
}});
}
}
})
export default store
使用的場景如下:
在組件中調用Action中的方法用的不是提交commit的方法,而是使用“分發”:通過 store.dispatch 方法觸發:
if (store.state.books.length === 0) {
store.dispatch('fetchData')
}
當然還可以在分發的時候傳遞參數:
methods: {
onSubmit: function() {
this.form.id = index++
this.form.bookname = "《" + this.form.bookname + "》"
store.dispatch('addItem', this.form)
.then((err) => {
if (!err) {
this.$message({
message: '添加成功!',
type: 'success'
})
} else {
this.$message.error('添加失敗!')
}
})
}
}
還可以通過對象的方法進行分發:
store.dispatch({
type: 'addItem',
newbook: this.form
}).then((err) => {
if (!err) {
this.$message({
message: '添加成功!',
type: 'success'
})
} else {
this.$message.error('添加失敗!')
}
})
Getter
getter可以看成是store的計算屬性,getter的值會根據他的依賴被緩存起來,當其依賴發生變化的時候其值纔會被重新計算:
const store = new Vuex.Store({
state: {
books: [],
},
getters: {
doneBooks: state => {
return state.books.filter(book => book.done)
}
}
})
在組件中的使用:
Getter 會暴露爲 store.getters 對象,通過屬性的形式訪問這些值:
store.getters.doneBooks
最後,什麼情況下應該使用 Vuex
Vuex的官方文檔提醒,Vuex雖然可以幫助我們管理共享狀態,但也附帶了更多的概念和框架。簡單的說就是如果你的項目較小,其狀態沒有複雜到需要使用Vuex來管理的時候,就不必使用Vuex。
轉載自: https://blog.csdn.net/shujh_sysu/article/details/79947418