Dieser Artikel stellt hauptsächlich die Verwendung von Vuex und die detaillierte Erklärung der Methode zur Beibehaltung des Zustands vor. Jetzt teile ich ihn mit Ihnen und gebe ihn als Referenz.
Vuex ist ein Zustandsverwaltungsmuster, das speziell für Vue.js-Anwendungen entwickelt wurde. Es verwendet einen zentralen Speicher, um den Status aller Komponenten der Anwendung zu verwalten, und stellt mithilfe entsprechender Regeln sicher, dass sich der Status auf vorhersehbare Weise ändert.
Als wir mit vuex in Kontakt kamen, war dies die erste offizielle Anleitung, die wir sahen.
Aus diesem Satz können wir die folgenden Informationen erhalten:
1. Vuex ist ein spezialisierter Flux, der für Vue existiert, genau wie die schwachen Entitäten in der Datenbank , Vuex kann nicht ohne Vue verwendet werden. Im Gegenteil, Sie können sehen, dass Redux nicht existiert. Unabhängig davon, ob es sich um Vue oder React handelt, kann Redux verwendet werden. Daher spiegeln sich die „Eigenschaften“ von Vuex hier wider, Redux hat „Universalität“
2. Die zentrale Verwaltung zeigt, dass der Status aller Komponenten in Vue in Vuex vorhanden ist
3. Bei Verwendung von Vuex, Sie müssen meine Regeln befolgen, damit ich die Änderungen im Zustand der Komponente verfolgen kann.
Das Bild oben ist Teil des Grundgerüsts des gesamten Vue-Projekts in diesem Artikel.
vuex verwendet einen einzelnen Statusbaum und unsere Vue-Anwendung enthält nur eine Store-Instanz. Wenn wir also den Store in der Vue-Instanz bereitstellen, können wir die verschiedenen Teile von Vuex über this.$store abrufen.
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 })
In der Indexdatei definieren wir den Anfangswert des Zustands, den wir in vuex speichern müssen.
Zum Beispiel habe ich im obigen Statusobjekt ein isLoading-Attribut gespeichert. Ich habe vor, dieses Attribut zu verwenden, um den Ladeeffekt zu identifizieren, der angezeigt wird, wenn ich die Backend-API anfordere, und nach Abschluss der Anforderung verschwindet. um die Wartementalität des Benutzers zu lindern.
Im Allgemeinen ist die in unseren Projekten am häufigsten verwendete Methode die Methode in mutation.js. Denn die einzige Möglichkeit, den Status im Store in vuex zu ändern, besteht darin, eine Mutation einzureichen.
In vuex hat jede Mutation einen String-Ereignistyp (Mutationstyp) und eine Rückruffunktion (Handler).
Diese Rückruffunktion kann zwei Parameter akzeptieren, der erste Parameter ist der Status und der zweite Parameter ist die Nutzlast der Mutation.
//... 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})
Eine andere Möglichkeit, eine Mutation einzureichen, besteht darin, direkt ein Objekt zu verwenden, das das Typattribut enthält. Ich empfehle diese Methode jedoch nicht, da der Code besser lesbar ist, wenn er auf die oben beschriebene Weise gehandhabt wird.
store.commit({ type: 'changeLoading', isLoading: true })
In Projekten, die die Zusammenarbeit mehrerer Personen erfordern, können wir Konstanten anstelle von Mutationsereignistypen verwenden. Dies ist ein sehr häufiges Muster in verschiedenen Flux-Implementierungen. Auch das Speichern dieser Konstanten in separaten Dateien macht die gemeinsame Entwicklung deutlich.
// mutation-types.js export const CHANGE_LOADING= 'CHANGE_LOADING' // mutation.js import { CHANGE_LOADING} from './mutation-types' export default{ [CHANGE_LOADING](state,payload){ state.isLoading = payload.isLoading }, }
Für die Definition der Ereignistypen in mutation-type halte ich mich grob an die folgenden von mir selbst definierten Spezifikationen:
1. Da eine Mutation einem Ereignis ähnelt, beginnt sie mit einem Verb
2. Wörter werden mit Unterstrichen verbunden
3. Der in vuex gespeicherte Zustand ist mit RECORD gekennzeichnet
Der lokal zwischengespeicherte Zustand ist mit SAVE gekennzeichnet
Natürlich können Sie diese Spezifikation selbst definieren, solange Sie die Absicht der Mutation anhand des Mutationstyps kennen.
Manchmal müssen wir einen Status aus dem Status im Store ableiten. Wie ich oben erwähnt habe, müssen wir beispielsweise einen Status anzeigen asynchrone Anfrage wird mit einer Maskenebene geladen, und dann muss ich den Ladestatus entsprechend dem Status unterhalb des Ladevorgangs anzeigen. Ohne die Verwendung von Gettern werden wir uns dafür entscheiden, berechnete Eigenschaften zu verwenden, um damit umzugehen.
computed: { loadingTxt () { return this.$store.state.isLoading ? '加载中' : '已完成'; } }
Unsere Ladung muss jedoch in vielen Komponenten verwendet werden. Dann müssen wir entweder die Funktion kopieren oder sie in eine gemeinsam genutzte Funktion extrahieren und an mehreren Stellen importieren – beides ist nicht ideal.
Wenn Sie Getter verwenden, wird alles schön.
//getter.js export default { loadingTxt:(state) =>{ return state.isLoading ? '加载中' : '已完成'; } };
Genau wie bei berechneten Eigenschaften wird der Rückgabewert eines Getters entsprechend seinen Abhängigkeiten zwischengespeichert und nur dann neu berechnet, wenn sich seine Abhängigkeitswerte ändern.
Darüber hinaus kann Getter auch andere Getter als zweiten Parameter akzeptieren:
export default { loadingTxt:(state) =>{ return state.isLoading ? '加载中' : '已完成'; }, isLoading:(state,getters) => { return 'string' === typeof getters.loadingTxt ? true : false; } };
Die Getter im Store können über die MapGetters-Hilfsfunktion
//组件中 import { mapGetters } from 'vuex' export default { data(){ return { //... } }, computed: { // 使用对象展开运算符将 getter 混入 computed 对象中 ...mapGetters([ 'loadingTxt', 'isLoading', // ... ]) } }
Die Funktion einer Aktion ähnelt der einer Mutation. Beide ändern den Zustand im Speicher. Es gibt jedoch zwei Unterschiede zwischen Aktion und Mutation:
1 . Bei Aktionen handelt es sich hauptsächlich um asynchrone Vorgänge, die synchron ausgeführt werden müssen, aber bei Aktionen können wir sowohl synchrone als auch asynchrone Vorgänge verarbeiten.
2. Aktionsänderungen Geben Sie schließlich die Mutation ein.
Nehmen Sie den Warenkorb als Beispiel. Wenn wir ein Produkt hinzufügen, müssen wir zuerst mit der SKU kommunizieren, oder wenn der Benutzer es nur hinzufügt, aber nicht und eine Bestellung aufgeben.
Wenn das Hinzufügen im Hintergrund erfolgreich ist, zeigt das Frontend das neu hinzugefügte Produkt an. Wenn dies fehlschlägt, müssen wir dem Benutzer mitteilen, dass das Hinzufügen fehlgeschlagen ist.
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 }) } ) } }
当我们的项目足够大的时候,单一的状态树这个时候就会显得很臃肿了。因为需要用vuex进行状态管理的状态全部集中在一个state对象里面。
所以,当一个东西大了以后,我们就要想办法进行分割,同样的道理,我们熟知的分冶法和分布式其实也是基于这样的一个思想在里面。而vuex提供了module,我们就可以去横向的分割我们的store。
比如说,我在项目中需要去做一个购物车这样的东西,这在电商的项目中也是常见的需求。
//shopCart.js import 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.js const 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.js const 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 }
用过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里面对应的值。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
在vue 2.x 中使用axios如何封装的get 和post方法
使用node应用中timing-attack存在哪些安全漏洞
Das obige ist der detaillierte Inhalt vonVerwendung von Vuex und Persistenz. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!