本篇內容主要講解“Vuex store怎么創建”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Vuex store怎么創建”吧!
創新互聯是一家以重慶網站建設公司、網頁設計、品牌設計、軟件運維、成都網站營銷、小程序App開發等移動開發為一體互聯網公司。已累計為成都純水機等眾行業中小客戶提供優質的互聯網建站和軟件開發服務。
自三大框架誕生起,它們共有的兩個能力徹底暴擊了 Jquery。這兩個能力分別是:
數據驅動視圖
組件化
數據驅動視圖,使我們告別了只能依靠操作 DOM 更新頁面的時代。我們不再需要每次更新頁面時,通過層層 find 找到 DOM 然后修改它的屬性和內容,可以通過操作數據來實現這些事情。
當然了在我們前端的眼里,數據基本可以理解為存儲各種數據類型的 變量
。在 數據驅動
這個概念出現之后,一部分變量也被賦予了特殊的含義。
首先是普通變量,和 JQ 時代沒差,僅用來存儲數據。除此之外還有一類變量,它們有響應式的作用,這些變量與視圖綁定,當變量改變時,綁定了這些變量的視圖也會觸發對應的更新,這類變量我稱之為狀態變量。
所謂數據驅動視圖,嚴格說就是狀態變量在驅動視圖。隨著 Vue,React 的大力普及之下,前端開發們的工作重心逐漸從操作 DOM 轉移到了操作數據,狀態變量成為了核心。
狀態變量,現在大家似乎更愿意稱之為狀態。我們經常詞不離口的狀態,狀態管理,其實這個狀態就是指狀態變量。下文提到的狀態同樣也是指狀態變量。
有了狀態之后,組件也來了。
JQ 時代的前端一個頁面就是一個 html,沒有“組件”的概念,對于頁面中的公共部分,想要優雅的實現復用簡直不要太難。所幸三大框架帶來了非常成熟的組件設計,可以很容易的抽取一個 DOM 片段作為組件,而且組件內部可以維護自己的狀態,獨立性更高。
組件的一個重要特性,就是內部的這些狀態是對外隔離的。父組件無法訪問到子組件內部的狀態,但是子組件可以訪問父組件顯示傳過來的狀態(Props),并且根據變化自動響應。
這個特性可以理解為狀態被模塊化了。這樣的好處是,不需要考慮當前設置的狀態會影響到其他組件。當然了組件狀態徹底隔離也是不現實的,必然會有多個組件共享狀態的需求,這種情況的方案就是將狀態提取到離這些組件最近的父組件,通過 Props 向下傳遞。
上述共享狀態的方案,在通常情況下是沒有問題的,也是一種官方建議的最佳實踐。
但是如果你的頁面復雜,你會發現還是有力不從心的地方。比如:
組件層級太深,需要共享狀態,此時狀態要層層傳遞。
子組件更新一個狀態,可能有多個父組件,兄弟組件共用,實現困難。
這種情況下繼續使用 “提取狀態到父組件” 的方法你會發現很復雜。而且隨著組件增多,嵌套層級加深,這個復雜度也越來越高。因為關聯的狀態多,傳遞復雜,很容易出現像某個組件莫名其妙的更新,某個組件死活不更新這樣的問題,異常排查也會困難重重。
鑒于此,我們需要一個更優雅到方案,專門去處理這種復雜狀況下的狀態。
上一節我們說到,隨著頁面的復雜,我們在跨組件共享狀態的實現上遇到了棘手的問題。
那么有沒有解決方案呢?當然有的,得益于社區大佬們的努力,方案還不止一個。但是這些方案都有一個共同的名字,就是我們在兩年前討論非常激烈的 ——— 狀態管理。
狀態管理,其實可以理解為全局狀態管理,這里的狀態不同于組件內部的狀態,它是獨立于組件單獨維護的,然后再通過某種方式與需要該狀態的組件關聯起來。
狀態管理各有各的實現方案。Vue 有 Vuex,React 有 Redux,Mobx,當然還有其他方案。但是它們解決的都是一個問題,就是跨組件狀態共享的問題。
我記得前兩年因為 “狀態管理” 這個概念的火熱,好像成了應用開發不可或缺的一部分。以 Vue 為例,創建一個項目必然會引入 Vuex 做狀態管理。但是很多人不知道為什么用,什么時候用,怎么用狀態管理,只是盲目跟風,于是后來出現了非常多濫用狀態管理的例子。
看到這里,你應該知道狀態管理不是必須的。它為什么出現,以及它要解決什么問題,上面基本都說明白了。如果你還沒明白,請暫停,從開頭再讀一遍。不要覺得一個技術方案誕生的背景不重要,如果你不明白它的出現是為了解決什么問題,那么你就無法真正發揮它的作用。
Redux 作者有一句名言:如果你不知道是否需要 Redux(狀態管理),那就是不需要它。
好了,如果你在用狀態管理,或需要使用狀態管理幫你解決問題,那我們繼續往下看。
Vue 在國內的應用非常廣泛,尤其是中小團隊,因此大多人接觸到的第一個狀態管理方案應該就是 Vuex。
那么 Vuex 是如何解決跨組件狀態共享的問題的呢?我們一起來探索一下。
我們上面說到,對于一般的組件共享狀態,官方建議“提取狀態到最近的父組件”。Vuex 則是更高一步,將所有狀態提取到了根組件,這樣任何組件都能訪問到。
也許你會問:這樣做不是把狀態暴露到全局了嗎?不就徹底消除模塊化的優勢了嗎?
其實不然。Vuex 這么做的主要目的是為了讓所有組件都可以訪問到這些狀態,徹底避免子組件狀態訪問不了的情況。Vuex 把所有狀態數據都放在一個對象上,遵循單一數據源的原則。但是這并不代表狀態是堆砌的,Vuex 在這顆單一狀態樹上實現了自己的模塊化方案。
別急,我們一步步來,先看看如何使用 Vuex。
Vuex 是作為 Vue 的插件存在的,首先 npm 安裝:
$ npm install --save vuex
安裝之后,我們新建 src/store
文件夾,在這里放所有 Vuex 相關的代碼。
新建 index.js
并寫入如下代碼。這段代碼主要的作用就是用 Vue.use
方法加載 Vuex 這個插件,然后將配置好的 Vuex.Store
實例導出。
import Vue from 'vue' import Vuex from 'vuex' // 安裝插件 Vue.use(Vuex) export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, modules: {} })
上面導出的實例我們通常稱之為 store
。一個 store 中包含了存儲的狀態(state
)和修改狀態的函數(mutation
)等,所有狀態和相關操作都在這里定義。
最后一步,在入口文件將上面導出的 store 實例掛載到 Vue 上:
import store from './store' new Vue({ el: '#app', store: store })
注意:掛載這一步不是必須的。掛載這一步的作用只是為了方便在 .vue 組件中通過 this.$store
訪問我們導出的 store 實例。如果不掛載,直接導入使用也是一樣的。
上一步我們用構造函數 Vuex.Store
創建了 store 實例,大家至少知道該怎么用 Vuex 了。這一步我們來看看 Vuex.Store 構造函數的具體配置。
首先是 state
配置,他的值是一個對象,用來存儲狀態。Vuex 使用 單一狀態樹
原則,將所有的狀態都放在這個對象上,便于后續的狀態定位和調試。
比如說我們有一個初始狀態 app_version
表示版本,如下:
new Vuex.Store({ state: { app_version: '0.1.1' } }
現在要在組件中獲取,可以這樣:
this.$store.state.app_version
但這并不是唯一的獲取方式,也可以這樣:
import store from '@/store' // @ 表示 src 目錄 store.state.app_version
為什么要強調這一點呢?因為很多小伙伴以為 Vuex 只能通過 this.$store
操作。到了非組件內,比如在請求函數中要設置某一個 Vuex 的狀態,就不知道該怎么辦了。
事實上組件中獲取狀態還有更優雅的方法,比如 mapState
函數,它讓獲取多狀態變得更簡單。
import { mapState } from 'vuex' export default { computed: { ... // 其他計算屬性 ...mapState({ version: state => state.app_version }) } }
Vuex 中的狀態與組件中的狀態不同,不能直接用 state.app_version='xx'
這種方式修改。Vuex 規定修改狀態的唯一方法是提交 mutation
。
Mutation 是一個函數,第一個參數為 state,它的作用就是更改 state 的狀態。
下面定義一個名叫 increment的 mutation,在函數內更新 count這個狀態:
new Vuex.Store({ state: { count: 1 }, mutations: { increment(state, count) { // 變更狀態 state.count += count } } })
然后在 .vue 組件中觸發 increment:
this.$store.commit('increment', 2)
這樣綁定了 count 的視圖就會自動更新。
雖然 mutation 是更新狀態的唯一方式,但實際上它還有一個限制:必須是同步更新。
為什么必須是同步更新?因為在開發過程中,我們常常會追蹤狀態的變化。常用的手段就是在瀏覽器控制臺中調試。而在 mutation 中使用異步更新狀態,雖然也會使狀態正常更新,但是會導致開發者工具有時無法追蹤到狀態的變化,調試起來就會很困難。
再有 Vuex 給 mutation 的定位就是更改狀態,只是更改狀態,別的不要參與。所謂專人干專事兒,這樣也幫助我們避免把更改狀態和自己的業務邏輯混起來,同時也規范了函數功能。
那如果確實需要異步更新,該怎么辦呢?
異步更新狀態是一個非常常見的場景,比如接口請求回來的數據要存儲,那就是異步更新。
Vuex 提供了 action
用于異步更新狀態。與 mutation 不同的是,action 不直接更新狀態,而是通過觸發 mutation 間接更新狀態。因此即便使用 action 也不違背 “修改狀態的唯一方法是提交 mutation” 的原則。
Action 允許在實際更新狀態前做一些副作用的操作,比如上面說的異步,還有數據處理,按條件提交不同的 mutation 等等。看一個例子:
new Vuex.Store({ state: { count: 1 }, mutations: { add(state) { state.count++ }, reduce(state) { state.count-- } }, actions: { increment(context, data) { axios.get('**').then(res => { if (data.iscan) { context.commit('add') } else { context.commit('reduce') } }) } } })
在組件中觸發 action:
this.$store.dispatch('increment', { iscan: true })
這些就是 action 的使用方法。其實 action 最主要的作用就是請求接口,拿到需要的數據,然后觸發 mutation 修改狀態。
其實這一步在組件中也可以實現。我看過一些方案,常見的是在組件內寫一個請求方法,當請求成功,直接通過 this.$store.commit
方法觸發 mutation 來更新狀態,完全用不到 action。
難道 action 可有可無嗎?
也不是,在特定場景下確實需要 action 的,這個會在下一篇說。
前面講過,Vuex 是單一狀態樹,所有狀態存放在一個對象上。同時 Vuex 有自己的模塊化方案
,可以避免狀態堆砌到一起,變的臃腫。
Vuex 允許我們將 store 分割成模塊(module),每個模塊擁有自己的 state、mutation、action。雖然狀態注冊在根組件,但是支持模塊分割,相當于做到了與頁面組件平級的“狀態組件”。
為了區分,我們將被分割的模塊稱為子模塊,暴露在全局的稱為全局模塊。
我們來看基礎用法:
new Vuex.Store({ modules: { user: { state: { uname: 'ruims' }, mutation: { setName(state, name) { state.name = name } } } } })
上面定義了 user
模塊,包含了一個 state 和一個 mutation。在組件中使用方法如下:
// 訪問狀態 this.$store.state.user.uname // 更新狀態 this.$store.commit('setName')
大家發現了,訪問子模塊的 state 要通過 this.$store.state.[模塊名稱]
這種方式去訪問,觸發 mutation 則與全局模塊一樣,沒有區別。
action 與 mutation 原理一致,不細說。
上面說到,子模塊觸發 mutation 和 action 與全局模塊一致,那么假設全局模塊和子模塊中都有一個名為 setName
的 mutation。在組件中觸發,哪個 mutation 會執行呢?
經過試驗,都會執行。官方的說法是:為了多個模塊能夠對同一 mutation 或 action 作出響應。
其實官方做的這個兼容,我一直沒遇到實際的應用場景,反而因為同名 mutation 導致誤觸發帶來了不少的麻煩。可能官方也意識到了這個問題,索引后來也為 mutation 和 action 做了模塊處理方案。
這個方案,就是命名空間。
命名空間也很簡單,在子模塊中加一個 namespaced: true
的配置即可開啟,如:
new Vuex.Store({ modules: { user: { namespaced: true, state: {} } } })
開啟命名空間后,觸發 mutation 就變成了:
this.$store.commit('user/setName')
可見提交參數由 '[mutation]'
變成了 '[模塊名稱]/[mutation]'
。
上面我們介紹了 Vuex 的模塊化方案,將單一狀態樹 store 分割成多個 module,各自負責本模塊狀態的存儲和更新。
模塊化是必要的,但是這個模塊的方案,用起來總覺得有點別扭。
比如,總體的設計是將 store 先分模塊,模塊下在包含 state,mutation,action。
那么按照正常理解,訪問 user 模塊下 state 應該是這樣的:
this.$store.user.state.uname
但是實際 API 卻是這樣的:
this.$store.state.user.uname
這個 API 仿佛是在 state 中又各自分了模塊。我沒看過源碼,但從使用體驗上來說,這是別扭一。
除 state 外,mutation,action 默認注冊在全局的設計,也很別扭。
首先,官方說的多個模塊對同一 mutation 或 action 作出響應,這個功能暫無找到應用場景。并且未配 namespace 時還要保證命名唯一,否則會導致誤觸發。
其次,用 namespace 后,觸發 mutation 是這樣的:
this.$store.commit('user/setName')
這個明顯是將參數單獨處理了,為什么不是這樣:
this.$store.user.commit('setName')
總體感受就是 Vuex 模塊化做的還不夠徹底。
上面說的槽點,并不是為了吐槽而吐槽。主要是感覺還有優化空間。
比如 this.$store.commit
函數可以觸發任何 mutation 來更改狀態。如果一個組件復雜,需要操作多個子模塊的狀態,那么就很難快速的找出當前組件操作了哪些子模塊,當然也不好做權限規定。
我希望的是,比如在 A 組件要用到 b, c
兩個子模塊的狀態,不允許操作其他子模塊,那么就可以先將要用到模塊導入,比如這樣寫:
import { a, b } from this.$store export default { methods: { test() { alert(a.state.uname) // 訪問狀態 a.commit('setName')// 修改狀態 } } }
這樣按照模塊導入,查詢和使用都比較清晰。
到此,相信大家對“Vuex store怎么創建”有了更深的了解,不妨來實際操作一番吧!這里是創新互聯網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
本文名稱:Vuexstore怎么創建
本文鏈接:http://www.yijiale78.com/article42/ihdgec.html
成都網站建設公司_創新互聯,為您提供品牌網站建設、、企業網站制作、搜索引擎優化、外貿網站建設、建站公司
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯