爲何會有 Vuex 這個東西 ?
現代前端框架主要解決的是 事件 -> 狀態 -> UI 將傳統前端在兩個過程的代碼剝離出來,變得更加容易維護;javascript
vue的聲明式渲染,解決了 狀態 和 UI 的同步問題,從而使咱們不須要因爲狀態發生改變去寫大量的命令式改變 dom 的代碼。html
而相似於 vuex 這類狀態管理的庫,則解決了 事件 -> 狀態 這個過程的維護問題。這類庫所作的事情就是管理從 事件源映射到狀態變化 這個過程(將這個映射過程從視圖組件中剝離出來,組織好這一部分的代碼,在組件外部進行狀態的管理)前端
具體表現就是一個全局的數據中心 store 配置,每一個組件進行更新的時候就通知數據中心,數據中心改變後,再去觸發每一個調用它的組件進行更新(這種更新是響應式的);幾個核心概念就是 mutations
裏的方法能夠直接 mutate
store 中的狀態,而且 mutation
過程必須同步的,須要經過 commit
去觸發;而 actions
則容許異步的操做,經過 commit
去觸發 mutation
,達到間接修改 store
的目的,action
自己須要經過 disptch
去觸發。vue
Vuex與全局對象的區別
其實,vuex
與全局對象有必定的共同之處,那就是狀態會被全局共享,不管是嵌套多少組件…java
每個 Vuex 應用的核心就是 store(倉庫)。「store」基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。Vuex 和單純的全局對象有如下兩點不一樣:git
- Vuex 的狀態存儲是 響應式 的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得 **高效更新 **。
- 你不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。
Vuex常見的應用場景
管理狀態與共享狀態程序員
應用簡單時,可使用 prop
與 event
來完成 父子組件 的通訊。使用 global event bus(event bus)
來實現 簡單的非父子組件之間的跨組件 通訊。但對於 **多層級組件嵌套 **等較爲複雜的場景,使用 vuex
能更好地應對。(使用 event bus 的缺點是當狀態較複雜,調用組件很是多,要挨個依次通知全部組件更新;每一個組件對這個組件進行的狀態更新都要通知監聽該事件的全部組件;這樣會變得很是複雜)github
vuex
狀態管理模型,擁有一個統一的數據中心Store,Store用來維護狀態數據;每一個組件進行更新的時候就通知數據中心,數據中心改變後,再去觸發每個調用它的組件進行更新(至關於由數據中心來統籌狀態變化以及狀態變化的分發,而不是由每一個vue
組件直接去操做state)vue-router
vuex
是經過將 state
做爲數據中心,各個組件 共享 state 來實現跨組件通訊的, 此時的數據徹底獨立於組件。(點擊不一樣模塊的操做,再也不須要去發送亂七八糟的事件, 只是去調用事件中內心的 mutation
動做, 從而實現模塊間共享狀態的功能)vuex
須要構建一箇中大型單頁應用時,極可能會考慮如何更好地 在組件外部 管理狀態
vuex更多地用於解決 **跨組件通訊 **(多層嵌套組件之間的通訊問題)以及做爲 數據中心集中式存儲數據 (管理應用中錯綜複雜的狀態關係)
vuex 做爲數據存儲中心
vuex
的 state
在單頁應用的開發中自己具備一個 數據庫 的做用,能夠將組件用到的數據存儲在 state
中,並在 actions
中封裝數據讀寫的邏輯。目前主要有兩種數據會使用 vuex
進行管理
- 組件之間 全局共享 的數據
- 經過後端異步請求的數據
實際項目開發中更多的是用到第二種,即把經過後端異步請求的數據都歸入 vuex
狀態管理,在 actions
中封裝數據的增刪改查等邏輯,這樣能夠在必定程度上對前端的邏輯代碼進行分層,使組件中的代碼更多地關注頁面交互與數據渲染等 視圖層 的邏輯,而異步請求與狀態數據的持久化等則交由 vuex
管理
通常全局數據,會使用到 vuex
來管理。好比 用戶數據,系統數據 等,這些數據不少組件中都會使用,咱們固然能夠每次使用的時候都去請求,可是出於程序員的「潔癖」、「摳」等等優勢,仍是但願一次請求,處處使用。
這時候很天然的想到存儲在 localStorage
中,可是有個問題是,這些數據可能會變,若是沒能及時 同步 的話,就會用到不正確的數據,即便作了數據同步,可是 localStorage
中的數據不是響應式的,不能自動更新使用到這些數據的地方。這時候就想要開始使用 vuex
了。
Vuex代碼的組織方式
與 vue-router
相似,有非模塊化寫法與模塊化寫法(其實不管何種寫法本質上是同樣的,目的就是導出一份 router
或者 store
的配置數據)
以管理 count
與 用戶信息 userinfo
爲例,介紹 vuex
代碼的組織方式
核心概念 state,getter,mutation,action,module
vuex
須要遵照的規則
應用層級的狀態應該集中到 單個 store
對象中
mutation
是直接操做state的方法(惟一能改變狀態的方法),過程要求必須同步
action
經過commit
去觸發mutation
,從而間接修改狀態,優勢是容許異步邏輯,
非模塊化寫法
// 1.安裝 vuex
// 2.在入口文件中引入
// main.js
import Vuex from 'vuex'
// 3.Vue使用 vuex 插件
Vue.use(Vuex)
// 4.生成數據管理中心 store
const store = new Vuex.Store({
state: {
userinfo: null, // 須要給定初始值
count: 0
},
// 直接經過mutation方法來mutate操做state; 只能以同步的方式; mutation方法須要經過commit來觸發
mutations: {
userinfo: function (state, payload) {
state.userinfo = options
localStorage.userinfo = JSON.stringify(state.userinfo)
},
increment: function (state, payload) {
state.count += payload.amount
}
},
// 經過commit觸發mutations裏的mutation方法, 以此間接修改 state; 容許異步操做;action方法須要經過dispatch來觸發
actions: {
increment: function (context, payload) {
context.commit('increment', payload)
},
incrementAsync: function (context) {
// 異步請求數據
setTimeout(() => {
var amount = 10; // 模擬異步請求獲得數據
context.commit('increment', { amount })
}, 1000)
},
async userinfo (context) {
let response = await getUserInfo() // 異步請求後端數據 方法須要 import
if (response.ok) {
let json = await response.json()
context.commit('userinfo', json)
}
}
},
getters: {// 處理、過濾數據
}
})
// 5.經過 store 配置參數注入狀態管理,從而任何組件可經過 this.$store 訪問狀態中心
new Vue({
el: '#app',
store, // (*)
render: function (h) {
return h(App)
}
})
模塊化寫法
// 1.安裝vuex
// 2.引入
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// import ...
// 3.Vue使用 vuex 插件
Vue.use(Vuex)
// 4.分模塊生成數據管理中心
// 配置 userinfo 狀態模塊 (還能再單獨拆出一個文件,而後import進來)
const moduleA = {
state: {
userinfo: null // 須要初始化響應式數據
},
mutations: {
userinfo: function (state, options) {
state.userinfo = options
localstorage.userinfo = JSON.stringify(state.userinfo)
}
},
actions: {
async userinfo (context) {
async userinfo (context) {
let response = await response.json()
if (response.ok) {
let json = await response.json()
context.commit('userinfo', json)
}
}
},
getters: {// 處理、過濾數據
}
}
}
// 配置 count 狀態模塊 (還能再單獨拆出一個文件,而後import進來)
const moduleB = {
state: {
count: 1,
},
mutations: {
increment:function (state, payload) {
state.count += payload
},
},
actions: {
increment: function (context, payload) {
context.comit('increment', payload)
},
incrementAsync: function (context) {
// 異步請求數據
setTimeout(() => {
var amount = 10; // 模擬異步請求獲得數據
context.commit('increment', { amount })
}, 1000)
},
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
// 5.導出一份 store 的配置
export default new Vuex.Store({
modules: { // 這裏與非模塊化寫法有點不同;原來整個對象是一份配置...
a: moduleA,
b: moduleB,
}
})
// store.state.a // -> moduleA 的狀態
// store.state.b // -> moduleB 的狀態
// 6.在根腳本 main.js 中引入 store 配置
import store from './store'
...
// 並經過 store 配置參數注入狀態管理,從而任何組件可經過 this.$store 訪問狀態中心
new Vue({
el: '#app',
router,
store,
render: function (h) {
return h(App);
}
});
在不一樣組件中使用或操做狀態
// 根組件
// App.vue
// 在生命週期中觸發全局共享數據的獲取
...
mounted () {
if (!this.$store.state.userinfo) { // this.$store.state.a.userinfo 模塊化寫法的話
this.$store.dispatch('userinfo')
}
}
// 使用 state 的數據
computed: {
userinfo () {
return this.$store.state.userinfo
// return this.$store.state.a.userinfo // 模塊化寫法的話
},
count () {
return this.$store.state.count
// return this.$store.state.b.count // 模塊化寫法的話
}
}
// 子組件
// NavBar.vue
...
// 改變 state 的數據
methods: {
// 使用 commit 觸發 mutations 中的 mutation 方法,直接修改 state 中的數據
addOne () {
this.$store.commit('increment', { amount: this.price })
},
// 使用 dispatch 觸發 actions 中的 action 方法;異步修改 state 中的數據
addTenAsync () {
this.$store.dispatch('incrementAsync')
}
}
// 使用 state 的數據
computed: {
userinfo () {
return this.$store.state.userinfo
// return this.$store.state.a.userinfo // 模塊化寫法的話
}
}
// 路由頁面組件
// Manage.vue
...
// 改變 state 的數據
methods: {
addTwo () {
this.$store.commit('increment', { amount: this.price })
}
}
// 使用 state 的數據
computed: {
count () {
return this.$store.state.count
// return this.$store.state.b.count // 模塊化寫法的話
}
},
總之,使用了 vuex
來管理狀態,點擊不一樣模塊的操做,再也不須要去發送亂七八糟的事件, 只是去調用事件中內心的 mutation
動做, 從而實現模塊間共享狀態的功能;修改一處,全局共享(不管是組件仍是路由頁面組件都能同步)
最後,再看看 vuex
官網的這張說明圖,是否是更加清晰了呢!
-項目地址- vuex-demo
原文出處:https://www.cnblogs.com/rencoo/p/12049831.html