国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

vuex的使用及持久化state的方式詳解

2019-11-19 14:29:32
字體:
來源:轉載
供稿:網友

Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化。

當我們接觸vuex的時候,這是我們最先看到的一句官方引導。

從這句話中,我們可以得到如下幾個信息:

1、vuex是一個為vue而存在的特化的Flux,如同數據庫中的弱實體一樣,離開了vue,vuex就用不了。反之可以看到redux就不存在,無論是vue還是react,redux都可以使用。所以這里體現的vuex的“特性”,redux則具備“普適性”

2、集中式的管理說明vue中所有的組件的狀態都是存在于vuex中

3、使用vuex你就要遵循我的規則,這樣組件中狀態的變化我才能跟蹤的到。

1.項目中vuex目錄的搭建

上圖是我在這篇文章中,vue整體項目骨架的局部。

vuex使用的是單一的狀態樹,我們的vue應用將僅僅包含一個 store 的實例。所以當我們將store掛載到vue的實例上以后,我們可以通過this.$store取到vuex里面的各個部分。

2.index.js

import vue from 'vue'import vuex from 'vuex'import mutations from './mutation'import getters from './getter'vue.use(vuex)const state = { isLoading:false}export default new vuex.Store({ state, getters, mutations})

在index這個文件中,我們會去定義我們需要在vuex中存儲的狀態初始值。

比如說,我在上面的state對象中去存儲了一個isLoading屬性,該屬性我準備用它來標識我請求backend API的時候顯示,在請求完成后消失的這樣一個loading的效果,來緩解一下用戶的等待心理。

3.Mutation(mutation.js)

一般來說,我們在項目中最常用的就是mutation.js里面的方法了。因為更改vuex中的store里的state的唯一的方式就是提交mutation。

在vuex中,每個mutation都有一個字符串的事件類型(mutation-type)和一個回調函數(handler)。

這個回調函數可接受兩個參數,第一個參數為state,第二參數是mutation的載荷(payload)。

//...mutations: { /** * @method:只傳入state,修改loading狀態 * @param {bool} isLoading:loading狀態 */  changeLoading(state) { state.isLoading = !state.isLoading }}store.commit('changeLoading')mutations: { /** * @method:傳入state和payload,修改loading狀態 * @param {bool} isLoading:loading狀態 */  changeLoading(state,payload) { state.isLoading = payload.isLoading }}store.commit('changeLoading',{isLoading: true})

還有一種提交mutation的方式是直接使用包含 type 屬性的對象,不過我不是很推薦這樣的方式,因為用上面的方式來處理的話,代碼的易讀性會更高。

store.commit({ type: 'changeLoading', isLoading: true})

4.mutation-types.js

在需要多人協作的項目中,我們可以使用常量代替mutation 事件類型。這在各種 Flux 實現中是很常見的模式。同時把這些常量放在單獨的文件中可以讓協作開發變得清晰。

// mutation-types.jsexport const CHANGE_LOADING= 'CHANGE_LOADING'// mutation.jsimport { CHANGE_LOADING} from './mutation-types'export default{ [CHANGE_LOADING](state,payload){  state.isLoading = payload.isLoading },}

對于定義mutation-type里面的事件類型,我大致遵循我自己定義的如下規范:

1、因為mutation類似于事件,所以以動詞開頭

2、單詞間以下劃線進行連接

3、保存到vuex里面的狀態用RECORD標識

4、緩存到本地的狀態用SAVE標識

 當然,這個規范的話大家可以自己定義,只要能通過mutation-type就能知道mutation的意圖就是極好的。

5.Getter(getter.js)

有時候我們需要從 store 中的 state 中派生出一些狀態,例如我上面提到的需要在異步請求的時候去顯示一個帶有遮罩層的loading,然后我loading的下面需要根據state去展示loading的狀態。在不使用getter的情況下,我們會選擇使用計算屬性去處理。

computed: { loadingTxt () { return this.$store.state.isLoading ? '加載中' : '已完成'; }}

但是,我們這個loading需要在很多的組件中去使用它。那么,我們要么復制這個函數,要么抽取到一個共享函數然后在多處導入它――無論哪種方式都不是很理想。

如果使用Getter,那么一切都變得美好了。

//getter.jsexport default { loadingTxt:(state) =>{  return state.isLoading ? '加載中' : '已完成'; } };

就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。

并且,Getter 也可以接受其他 getter 作為第二個參數:

export default { loadingTxt:(state) =>{  return state.isLoading ? '加載中' : '已完成'; },  isLoading:(state,getters) => {  return 'string' === typeof getters.loadingTxt ? true : false; } };

通過mapGetters輔助函數可以將 store 中的 getter 映射到局部計算屬性

//組件中import { mapGetters } from 'vuex'export default { data(){ return {  //... } }, computed: { // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([  'loadingTxt',  'isLoading',  // ... ]) }}

6.Action(action.js)

action的功能和mutation是類似的,都是去變更store里的state,不過action和mutation有兩點不同:

1、action主要處理的是異步的操作,mutation必須同步執行,而action就不受這樣的限制,也就是說action中我們既可以處理同步,也可以處理異步的操作

2、action改變狀態,最后是通過提交mutation

就拿購物車來說,當我們去添加一個商品的時候,我們需要先和后臺去通訊一次,這里涉及到sku或者說是如果用戶只添加了但是沒有去下單。

如果后臺添加成功,前端再去展示新添加的商品,如果失敗,我們需要告訴用戶添加失敗了。

const actions = { checkout ({    state,      commit,   //rootState       }, products) { const savedCartItems = [...state.added] commit(SET_CHECKOUT_STATUS, null) // 置空購物車 commit(SET_CART_ITEMS, { items: [] }) shop.buyProducts(  products,   //成功  () => commit(SET_CHECKOUT_STATUS, 'successful'),  //失敗  () => {  commit(SET_CHECKOUT_STATUS, 'failed')  commit(SET_CART_ITEMS, { items: savedCartItems })  } ) }}

7.module

當我們的項目足夠大的時候,單一的狀態樹這個時候就會顯得很臃腫了。因為需要用vuex進行狀態管理的狀態全部集中在一個state對象里面。

所以,當一個東西大了以后,我們就要想辦法進行分割,同樣的道理,我們熟知的分冶法和分布式其實也是基于這樣的一個思想在里面。而vuex提供了module,我們就可以去橫向的分割我們的store。

比如說,我在項目中需要去做一個購物車這樣的東西,這在電商的項目中也是常見的需求。

//shopCart.jsimport shop from '../../api/shop'import { ADD_TO_CART, SET_CART_ITEMS, SET_CHECKOUT_STATUS} from '../mutation-types'const state = { added: [], checkoutStatus: null}/** * module getters * @param {Object} state:模塊局部state * @param {Object} getters:模塊局部getters,會暴露到全局 * @param {Object} rootState:全局(根)state */const getters = { checkoutStatus: state => state.checkoutStatus, cartProducts: (state, getters, rootState) => { return state.added.map(({ id, quantity }) => {  const product = rootState.products.all.find(product => product.id === id)  return {  title: product.title,  price: product.price,  quantity  } }) }, cartTotalPrice: (state, getters) => { return getters.cartProducts.reduce((total, product) => {  return total + product.price * product.quantity }, 0) }}/** * module actions * @param {Object} state:模塊局部state * @param {Object} getters:模塊局部getters,會暴露到全局 * @param {Object} rootState:全局(根)state */const actions = { checkout ({    state,      commit,   //rootState       }, products) { const savedCartItems = [...state.added] commit(SET_CHECKOUT_STATUS, null) // 置空購物車 commit(SET_CART_ITEMS, { items: [] }) shop.buyProducts(  products,   //成功  () => commit(SET_CHECKOUT_STATUS, 'successful'),  //失敗  () => {  commit(SET_CHECKOUT_STATUS, 'failed')  commit(SET_CART_ITEMS, { items: savedCartItems })  } ) }}/** * module mutations * @param {Object} state:模塊局部state * @param payload:mutation的載荷 */const mutations = { //用id去查找商品是否已存在, [ADD_TO_CART] (state, { id }) { state.checkoutStatus = null const record = state.added.find(product => product.id === id) if (!record) {  state.added.push({  id,  quantity: 1  }) } else {  record.quantity++ } }, [SET_CART_ITEMS] (state, { items }) { state.added = items }, [SET_CHECKOUT_STATUS] (state, status) { state.checkoutStatus = status }}export default { state, getters, actions, mutations}

在module的定義的局部state,getters,mutation,action中,后三個都會暴露到全局的store中去,這樣使得多個模塊能夠對同一 mutation 或 action 作出響應。就不需要在其他的模塊中去定義相同的mutation或action了。

而這里的state是局部的。這也導致后來的持久化無法去處理用module分割后的state。

如同上面的module =》shopCart,

當我們無論是在index.js里面或者其他的module中,shopCart里面的getters或者action或者mutations,我們都可以去使用。

//test.jsconst state = { isTest:false};const getters = { isTest :state => state.isTest, checkTestStatus:(state,getters) => { return getters.checkoutStatus; }};export default { state, getters,}//組件中...mapGetters([ 'checkTestStatus'])//...created(){ this.checkTestStatus ;//null}

如果說,我就想讓我的module里面的定義的全部都是獨享的。我們可以使用module的命名空間,通過設置namespaced: true。

//test.jsconst getters = { // 在這個模塊的 getter 中,`getters` 被局部化了 // 你可以使用 getter 的第四個參數來調用 `rootGetters` someGetter (state, getters, rootState, rootGetters) { getters.someOtherGetter // 'test/someOtherGetter' rootGetters.someOtherGetter // 'someOtherGetter' }, someOtherGetter: state => { ... }};const actions = { // 在這個模塊中, dispatch 和 commit 也被局部化了 // 他們可以接受 `root` 屬性以訪問根 dispatch 或 commit someAction ({ dispatch, commit, getters, rootGetters }) { getters.someGetter // 'test/someGetter' rootGetters.someGetter // 'someGetter' dispatch('someOtherAction') // 'test/someOtherAction' dispatch('someOtherAction', null, { root: true }) // 'someOtherAction' commit('someMutation') // 'test/someMutation' commit('someMutation', null, { root: true }) // 'someMutation' }, someOtherAction ({ state,commit }, payload) { ... }}export default { namespaced: true, state, getters, actions, mutations}

8.持久化state的工具:vuex-persistedstate

用過vuex的肯定會有這樣一個痛點,就是刷新以后vuex里面存儲的state就會被瀏覽器釋放掉,因為我們的state都是存儲在內存中的。

而像登錄狀態這樣的東西,你不可能一刷新就讓用戶重新去登錄吧!所以,我們會去選擇把狀態存儲到本地。

這樣一來問題貌似是解決了,但是當我們需要使用的時候,我們就需要不斷的從本地,通過getStore這樣的方法去取得我們state。如果需要更新的話,我們又要在mutation里面通過setStore這樣的方法去處理它。

雖然,我們的setStore都是在操作了state以后再去調用的,也就是說無論是通過vuex的logger或者vue的dev tool我們都是可以對local里面的狀態進行跟蹤的,但是,我們無法保證我們每次都記著去寫setStore。

這樣一來,在共享state的組件中,我們的代碼可能就會是這樣的。

import { getStore } from '@/util'//組件中mounted(){ this.foo = getStore('foo'); this.bar = getStore('bar'); //.... }

那么,如何去改進呢?

我們能想到的就是,能不能讓state不是保存在內存中,而是存儲在本地。

而vuex-persistedstate做了這樣的事情,它幫我們將store里面的state映射到了本地環境中。這樣一來,我通過提交mutation改變的state,會動態的去更新local里面對應的值。

大家感興趣的話,可以戳這里,這里有個小dmeo

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 富蕴县| 靖西县| 滨海县| 龙门县| 洛宁县| 天津市| 祁东县| 鸡泽县| 通城县| 万安县| 腾冲县| 鱼台县| 庆云县| 湘潭市| 汝州市| 东城区| 澎湖县| 台湾省| 临夏市| 屯昌县| 灌云县| 富顺县| 河北省| 蓝田县| 偃师市| 泸定县| 白银市| 封丘县| 都昌县| 霍山县| 大悟县| 茌平县| 乌拉特前旗| 南康市| 同心县| 甘肃省| 司法| 海林市| 泸州市| 兴义市| 游戏|