Maison > interface Web > js tutoriel > le corps du texte

Utiliser vuex et la persistance

亚连
Libérer: 2018-06-09 18:04:54
original
1854 Les gens l'ont consulté

Cet article présente principalement l'utilisation de vuex et l'explication détaillée de la méthode d'état persistant. Maintenant, je le partage avec vous et le donne comme référence.

Vuex est un modèle de gestion d'état développé spécifiquement pour les applications Vue.js. Il utilise un stockage centralisé pour gérer l'état de tous les composants de l'application et utilise les règles correspondantes pour garantir que l'état change de manière prévisible.

Lorsque nous sommes entrés en contact avec vuex, c'était la première guidance officielle que nous avons vue.

De cette phrase, nous pouvons obtenir les informations suivantes :

1. vuex est un Flux spécialisé qui existe pour vue, tout comme dans la base de données Comme les entités faibles. , vuex ne peut pas être utilisé sans vue. Au contraire, vous voyez que redux n'existe pas. Que ce soit vue ou réagir, redux peut être utilisé. Par conséquent, les "caractéristiques" de vuex reflétées ici, redux a une "universalité"

2. La gestion centralisée montre que l'état de tous les composants dans vue existe dans vuex

3. Lors de l'utilisation de vuex, vous devez suivre mes règles, afin que je puisse suivre les changements d'état du composant.

1. Construction du répertoire vuex dans le projet

L'image ci-dessus fait partie du squelette du projet vue global dans cet article.

vuex utilise une seule arborescence d'états et notre application vue ne contiendra qu'une seule instance de magasin. Ainsi, lorsque nous montons le magasin sur l'instance de vue, nous pouvons obtenir les différentes parties de vuex via this.$store.

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
})
Copier après la connexion

Dans le fichier d'index, nous définirons la valeur initiale de l'état que nous devons stocker dans vuex.

Par exemple, j'ai stocké un attribut isLoading dans l'objet state ci-dessus. Je prévois d'utiliser cet attribut pour identifier l'effet de chargement qui sera affiché lorsque je demande l'API backend et disparaîtra une fois la demande terminée. pour soulager la mentalité d'attente de l'utilisateur.

3.Mutation (mutation.js)

De manière générale, la méthode la plus couramment utilisée dans nos projets est la méthode dans mutation.js. Parce que la seule façon de changer l'état du magasin dans vuex est de soumettre une mutation.

Dans vuex, chaque mutation a un type d'événement chaîne (mutation-type) et une fonction de rappel (gestionnaire).

Cette fonction de rappel peut accepter deux paramètres, le premier paramètre est l'état et le deuxième paramètre est la charge utile de la 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})
Copier après la connexion

Une autre façon de soumettre une mutation consiste à utiliser directement un objet contenant l'attribut type. Cependant, je ne recommande pas cette méthode car le code sera plus lisible s'il est traité de la manière ci-dessus.

store.commit({
 type: 'changeLoading',
 isLoading: true
})
Copier après la connexion

4.mutation-types.js

Dans les projets qui nécessitent une collaboration entre plusieurs personnes, nous pouvons utiliser des constantes au lieu de types d'événements de mutation. Il s'agit d'un modèle très courant dans diverses implémentations de Flux. Le fait de conserver ces constantes dans des fichiers séparés rend également clair le développement collaboratif.

// 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
 },
}
Copier après la connexion

Pour définir les types d'événements en mutation-type, je suis grossièrement les spécifications suivantes définies par moi-même :

1 Parce que la mutation est similaire à un événement, elle commence par un verbe.

2. Les mots sont connectés par des traits de soulignement

3. L'état enregistré dans vuex est marqué par RECORD

4 L'état mis en cache localement est marqué par SAVE

<. 🎜> Bien sûr, vous pouvez définir cette spécification vous-même, tant que vous pouvez connaître l'intention de la mutation par type de mutation, c'est excellent.

5. Getter (getter.js)

Parfois, nous devons dériver un statut de l'état dans le magasin. Par exemple, comme je l'ai mentionné ci-dessus, nous devons afficher un statut lors d'un achat. requête asynchrone Chargement avec un calque de masque, puis je dois afficher l'état de chargement en fonction de l'état en dessous du chargement. Sans utiliser de getters, nous choisirons d'utiliser des propriétés calculées pour le gérer.

computed: {
 loadingTxt () {
 return this.$store.state.isLoading ? &#39;加载中&#39; : &#39;已完成&#39;;
 }
}
Copier après la connexion
Cependant, notre chargement doit être utilisé dans de nombreux composants. Ensuite, soit nous copions la fonction, soit nous l'extrayons dans une fonction partagée et l'importons à plusieurs endroits - dans les deux cas, ce n'est pas idéal.

Si vous utilisez Getter, tout devient beau.

//getter.js
export default {
 loadingTxt:(state) =>{
  return state.isLoading ? &#39;加载中&#39; : &#39;已完成&#39;;
 } 
};
Copier après la connexion
Tout comme les propriétés calculées, la valeur de retour d'un getter sera mise en cache en fonction de ses dépendances, et ne sera recalculée que lorsque ses valeurs de dépendance changeront.

Et Getter peut également accepter d'autres getters comme deuxième paramètre :

export default {
 loadingTxt:(state) =>{
  return state.isLoading ? &#39;加载中&#39; : &#39;已完成&#39;;
 },
  isLoading:(state,getters) => {
  return &#39;string&#39; === typeof getters.loadingTxt ? true : false;
 } 
};
Copier après la connexion
Les getters du magasin peuvent être mappés à des propriétés calculées locales via la fonction auxiliaire mapGetters

//组件中
import { mapGetters } from &#39;vuex&#39;

export default {
 data(){
 return {
  //...
 }
 },
 computed: {
 // 使用对象展开运算符将 getter 混入 computed 对象中
 ...mapGetters([
  &#39;loadingTxt&#39;,
  &#39;isLoading&#39;,
  // ...
 ])
 }
}
Copier après la connexion
6.Action (action.js)

La fonction de l'action est similaire à la mutation, qui changent toutes deux l'état dans le magasin, mais il existe deux différences entre l'action et la mutation :

1. L'action gère principalement les opérations asynchrones. La mutation doit être exécutée de manière synchrone, mais l'action n'est pas soumise à de telles restrictions.

2. l'action change l'état et soumet finalement la mutation

Prenons l'exemple du panier Lorsque nous ajoutons un produit, nous devons d'abord communiquer avec le backend. Cela implique le SKU ou si l'utilisateur l'a seulement ajouté, mais. Je n'ai pas passé la commande.

Si l'ajout en arrière-plan réussit, le front-end affichera le produit nouvellement ajouté. S'il échoue, nous devons informer l'utilisateur que l'ajout a échoué.

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, &#39;successful&#39;),
  //失败
  () => {
  commit(SET_CHECKOUT_STATUS, &#39;failed&#39;)
  commit(SET_CART_ITEMS, { items: savedCartItems })
  }
 )
 }
}
Copier après la connexion

7.module

当我们的项目足够大的时候,单一的状态树这个时候就会显得很臃肿了。因为需要用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, &#39;successful&#39;),
  //失败
  () => {
  commit(SET_CHECKOUT_STATUS, &#39;failed&#39;)
  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
}
Copier après la connexion

在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([
 &#39;checkTestStatus&#39;
])
//...
created(){
 this.checkTestStatus ;//null
}
Copier après la connexion

如果说,我就想让我的module里面的定义的全部都是独享的。我们可以使用module的命名空间,通过设置namespaced: true。

//test.js
const getters = {
 // 在这个模块的 getter 中,`getters` 被局部化了
 // 你可以使用 getter 的第四个参数来调用 `rootGetters`
 someGetter (state, getters, rootState, rootGetters) {
 getters.someOtherGetter // &#39;test/someOtherGetter&#39;
 rootGetters.someOtherGetter // &#39;someOtherGetter&#39;
 },
 someOtherGetter: state => { ... }
};

const actions = {
 // 在这个模块中, dispatch 和 commit 也被局部化了
 // 他们可以接受 `root` 属性以访问根 dispatch 或 commit
 someAction ({ dispatch, commit, getters, rootGetters }) {
 getters.someGetter // &#39;test/someGetter&#39;
 rootGetters.someGetter // &#39;someGetter&#39;

 dispatch(&#39;someOtherAction&#39;) // &#39;test/someOtherAction&#39;
 dispatch(&#39;someOtherAction&#39;, null, { root: true }) // &#39;someOtherAction&#39;

 commit(&#39;someMutation&#39;) // &#39;test/someMutation&#39;
 commit(&#39;someMutation&#39;, null, { root: true }) // &#39;someMutation&#39;
 },
 someOtherAction ({ state,commit }, payload) { ... }
}

export default {
 namespaced: true,
 state,
 getters,
 actions,
 mutations
}
Copier après la connexion

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 &#39;@/util&#39;
//组件中
mounted(){
 this.foo = getStore(&#39;foo&#39;);
 this.bar = getStore(&#39;bar&#39;);
 //.... 
}
Copier après la connexion

那么,如何去改进呢?

我们能想到的就是,能不能让state不是保存在内存中,而是存储在本地。

而vuex-persistedstate做了这样的事情,它帮我们将store里面的state映射到了本地环境中。这样一来,我通过提交mutation改变的state,会动态的去更新local里面对应的值。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在bootstrap中如何实现table支持高度百分比

在vue 2.x 中使用axios如何封装的get 和post方法

使用node应用中timing-attack存在哪些安全漏洞

在vue组件传递对象中实现单向绑定,该怎么做?

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal