Fermer

mars 22, 2019

Vuex – La plongée profonde


Cet article plonge dans Vuex, une bibliothèque de gestion d'état de Vue.js. Nous examinerons les problèmes qu'il a été créé pour résoudre le problème, les concepts de base qui le sous-tendent, comment le configurer et, bien sûr, utiliser des exemples de code à chaque étape du processus.

Vuex est une bibliothèque de gestion d'état construite. par l'équipe de Vue pour la gestion des données dans les applications Vue.js. Il fournit un moyen centralisé de gestion des données utilisées dans l'application et facilite les actions de lecture et d'écriture.

Pourquoi Vuex?

Vue favorise la décomposition des vues en composants. Ces composants sont des instances Vue réutilisables qui acceptent des données, des méthodes, etc. Les données indiquent l'emplacement de l'état de la vue, tandis que la méthode permet de manipuler cet état en fonction des interactions de l'utilisateur avec la vue.

un utilisateur clique sur un bouton dans un composant, une méthode est appelée, qui exécute à son tour une action sur ledit état tandis que ledit état met à jour la vue concernant ce changement.

Cependant, il arrive parfois que plusieurs composants doivent être partagés. un état ou après la modification d'un état dans un composant, vous avez besoin du composant parent / enfant ou frère pour effectuer une action de suivi.

Selon la position de ce second composant, vous pouvez décider d'utiliser . props ou le mot-clé this. $ parent pour accéder directement aux données ou aux méthodes du second composant et effectuer ladite action. Mais si vous devez le faire pour autant de composants que possible?

À mesure que le projet grossit, vous vous retrouvez en train de faire des accessoires et de manipuler directement le DOM pour accéder à divers composants.

Cette approche devient très fastidieuse et rend également la base de code difficile à maintenir ou à déboguer lorsque vous rencontrez des erreurs. C’est là que Vuex brille. Il fournit une étendue globale dans laquelle vous pouvez placer tous les états qui seraient partagés entre les divers composants.

Il donne également à notre code plus de structure, facilite le débogage, car nous pouvons utiliser les outils de développement pour suivre les erreurs qui se produisent et fournit bien sûr la réactivité que Vue apporte à la table. Pensez-y comme aux fenêtres en JavaScript & mdash; chaque composant y a accès.

Installation de Vuex

Pour installer Vuex dans un projet, exécutez le code ci-dessous.

 npm install vuex --save 

Ceci installera la dernière version de Vuex dans votre projet. . Une fois que cela est fait, nous devons initialiser Vuex dans l'application Vue en créant notre fichier store.js avec le code ci-dessous;

 importez Vue depuis 'vue'
importer Vuex depuis 'vuex'

Vue.use (Vuex) 

Nous pouvons maintenant créer un magasin. Le magasin est essentiellement un objet réactif contenant l'état, les accesseurs, les mutations et les actions de l'application.

Comprendre le magasin

Le magasin est essentiellement un État centralisé, doté de concepts fondamentaux permettant de réaliser cette centralisation. Ces concepts incluent:

  1. State
        
  2. Getters
        
  3. Mutations
        
  4. Actions
        

Etat

Il s'agit d'un seul objet contenant toutes les données. Ceci est similaire au mot-clé data de la structure à composants uniques, sauf que cet état est accessible à partir de plusieurs composants et que, lorsque cet état est mis à jour, tous les composants qui y accèdent reçoivent également cette modification. Pour créer cet objet, nous faisons ce qui suit:

 // import Vue
importer Vue de 'vue';
// importer Vuex
importer Vuex depuis 'vuex';

// Installer le plugin Vuex sur vue
Vue.use (Vuex);

// créer une instance de magasin Vuex
export const store = new Vuex.Store ({
    Etat: {
        Chariot: ''
    }
}) 

Pour accéder à l'état Vuex dans nos composants Vue, nous devions d'abord importer le magasin dans le composant en créant une propriété calculée qui renverrait ledit état, puis rendrait ledit état à la vue.

Maintenant, importons le magasin. Il existe deux manières principales de procéder:

  1. Importer manuellement le magasin dans chaque composant que vous êtes sur le point d'utiliser l'état Vuex, comme suit:
        

     & lt; modèle & gt;
        & lt; main & gt;
            & lt; h1 & gt; Contenu du panier & lt; / h1 & gt;
            & lt; p & gt; {{cartValue}} & lt; / p & gt;
        & lt; / main & gt;
    & lt; / template & gt;
    
    & lt; script & gt;
    // Importer Vuex Store dans un composant
    importer magasin de 'store.js';
    défaut d'exportation {
        calculé: {
            cartValue () {
                // Renvoie l'état Vuex du magasin
                return store.state.cart;
            }
        }
    }
    & lt; / script & gt;
    
  2. Réaliser une injection globale du magasin Vuex dans l'instance Vue, ce qui nous donne automatiquement le droit de référencer le magasin à partir de tous les composants Vue de l'application à l'aide de la syntaxe this. $ Store :
        

     importer Vue de 'vue';
    importer magasin de './store.js';
    
    nouveau Vue ({
        // Ajout du magasin Vuex à l'instance Vue
        le magasin,
    }). $ mount ('# app');
     

        

     & lt; modèle & gt;
        & lt; main & gt;
            & lt; h1 & gt; Contenu du panier & lt; / h1 & gt;
            & lt; p & gt; {{cartValue}} & lt; / p & gt;
        & lt; / main & gt;
    & lt; / template & gt;
    
    & lt; script & gt;
    défaut d'exportation {
        calculé: {
            cartValue () {
                // Accéder à l'état Vuex
                renvoyer cette. $ store.state.cart;
            }
        }
    }
    & lt; / script & gt;
    

Getters

Les getters sont des propriétés calculées pour le magasin Vuex. Ils nous permettent de générer un nouvel état basé sur l’état actuel & mdash; par exemple, calculer le nombre d'éléments contenus dans le panier.

Cela permet également de réduire la duplication de code là où idéalement plusieurs composants ont besoin de ces données et que nous devrions normalement manipuler dans chaque composant. Avec les getters, nous pouvons le faire une fois et référence n'importe où.

Pour créer un getter, nous procédons comme suit:

 // import Vue
importer Vue de 'vue';
// importer Vuex
importer Vuex depuis 'vuex';

// Installer le plugin Vuex sur vue
Vue.use (Vuex);

// créer une instance de magasin Vuex
export const store = new Vuex.Store ({
    Etat: {
        panier: ["bread", "rice", "beans", "turkey"]
    },
  
    getters: {
        // Récupère le nombre total d'articles dans le panier
        totalNumberOfCartItems: state = & gt; {
            return state.cart.length;
        },
    },
})

Ensuite, nous accédons au getter depuis notre composant Vue en procédant ci-dessous:

 & lt; modèle & gt;
    & lt; main & gt;
        & lt; h1 & gt; Contenu du panier & lt; / h1 & gt;
        & lt; p & gt; Nombre total d'éléments: {{totalNumberOfCartItems}} & lt; / p & gt;
    & lt; / main & gt;
& lt; / template & gt;

& lt; script & gt;
défaut d'exportation {
    calculé: {
        totalNumberOfCartItems () {
            // Accéder à l'état Vuex
            retourne cette. $ store.getters.totalNumberOfCartItems;
        }
    }
}
& lt; / script & gt;

Chaque fois qu'un article est ajouté au panier, le nombre total d'articles dans le panier est mis à jour automatiquement.

Mutations

Les mutations sont le seul moyen de mettre à jour notre état Vuex. Ils effectuent une tâche et une seule tâche: définir un état. C'est une fonction qui prend deux arguments, l'état et une charge utile, où la charge utile n'est pas nécessairement requise

La charge utile est simplement les données qui seraient utilisées pour mettre à jour l'état. Les mutations sont synchrones et, en tant que telles, nous ne pouvons pas y exécuter de tâche asynchrone.

Ajoutons maintenant une mutation à notre code:

 // import Vue
importer Vue de 'vue';
// importer Vuex
importer Vuex depuis 'vuex';

// Installer le plugin Vuex sur vue
Vue.use (Vuex);

// créer une instance de magasin Vuex
export const store = new Vuex.Store ({
    Etat: {
        panier: ["bread", "rice", "beans", "turkey"]
    },
  
    getters: {
        // Récupère le nombre total d'articles dans le panier
        totalNumberOfCartItems: state = & gt; {
            return state.cart.length;
        },
    },
    
    mutations: {
        // Ajouter un article au panier
        addItemToCart (état, charge utile) {
            state.cart.push (charge utile);
        },
    },
})

Ensuite, nous devons mettre à jour l'état à partir de notre composant Vue et, pour ce faire, nous devons valider la mutation.

 & lt; modèle & gt;
    & lt; main & gt;
        & lt; h1 & gt; Contenu du panier & lt; / h1 & gt;
        & lt; p & gt; Nombre total d'éléments: {{totalNumberOfCartItems}} & lt; / p & gt;
        & lt; form @ submit.prevent = "addItemToCart" & gt;
            & lt; input type = "text" v-model = "item" requis & gt;
            & lt; button type = "submit" & gt; Ajouter au panier & lt; / button & gt;
        & lt; / form & gt;
    & lt; / main & gt;
& lt; / template & gt;

& lt; script & gt;
défaut d'exportation {
    Les données() {
        revenir {
            article: ''
        }
    },
    calculé: {
        totalNumberOfCartItems () {
            // Accéder à l'état Vuex
            retourne cette. $ store.getters.totalNumberOfCartItems;
        }
    },
    méthodes: {
        addItemToCart () {
            // Vérifie que le champ de saisie n'est pas vide
            if (this.item! == '') {
                // commettre la mutation additemtocart avec la charge utile
                this. $ store.commit ('addItemToCart', this.item)
            }
        }
    }
}
& lt; / script & gt;

Chaque fois qu'un utilisateur entre une valeur dans l'entrée et clique sur le bouton de validation, l'élément est ajouté au panier et le nombre total d'éléments dans le panier est mis à jour dans la vue.

Actions

semblable aux mutations, mais au lieu de muter l’état, ils commettent des mutations. Ils sont asynchrones et, en tant que tels, nous permettent d’effectuer des tâches asynchrones. lorsque ces tâches sont terminées, nous procédons à la validation d'une mutation, qui à son tour met à jour l'état.

Pour mettre en évidence les actions, nous allons procéder à la soumission des éléments du panier à un API.

 // import Vue
importer Vue de 'vue';
// importer Vuex
importer Vuex depuis 'vuex';

// Installer le plugin Vuex sur vue
Vue.use (Vuex);

// créer une instance de magasin Vuex
export const store = new Vuex.Store ({
    Etat: {
        panier: ["bread", "rice", "beans", "turkey"]
    },
  
    getters: {
        // Récupère le nombre total d'articles dans le panier
        totalNumberOfCartItems: state = & gt; {
            return state.cart.length;
        },
    },
    
    mutations: {
        // Ajouter un article au panier
        addItemToCart (état, charge utile) {
            state.cart.push (charge utile);
        },
        // Effacer les articles dans le panier
        emtpyCart (state) {
            state.cart = [];
        }
    },
    
    actes: {
        checkout ({commit}, requestObject) {
            // Appel API pour soumettre les articles dans le panier
            Vue.http.post ('submit', requestObject) .then ((response) = & gt; {
                // journal des succès
                console.log (réponse);
                // Efface le panier en modifiant l'état
                commit ('emptyCart');
            }). catch ((error) = & gt; {
                // erreur de journal
                console.log (erreur);
            }
        }
    }
})

En regardant le code ci-dessus, nous avons créé une action appelée checkout qui accepte deux choses:

  1. commit : qui nous permet d'appeler la méthode commit dans nos actions.
        
  2. requestObject : qui permet de passer des données à l'action
        

Passant à l'action, nous avons fait un appel asynchrone à une API, puis nous avons transmis l'objet requestObject à l'API. En cas de succès, nous avons enregistré la réponse, puis effacé l'état du panier, mais nous devions d'abord créer une mutation emptyCart dont la tâche singulière est de vider l'état du panier.

Maintenant que nous avons vu comment créer des actions, nous procédons au déclenchement de cette action. Pour déclencher une action, Vuex nous fournit une commande dispatch .

this. $ Store.dispatch ('actionName', charge utile);

Laissez-nous ajouter un action dans notre code et l'envoyer à partir de la vue:

 & lt; modèle & gt;
    & lt; main & gt;
        & lt; h1 & gt; Contenu du panier & lt; / h1 & gt;
        & lt; p & gt; Nombre total d'éléments: {{totalNumberOfCartItems}} & lt; / p & gt;
        & lt; form @ submit.prevent = "addItemToCart" & gt;
            & lt; input type = "text" v-model = "item" requis & gt;
            & lt; button type = "submit" & gt; Ajouter au panier & lt; / button & gt;
        & lt; / form & gt;
        
        & lt; button type = "button" @ click = "checkout" & gt; Commander & lt; / button & gt;
    & lt; / main & gt;
& lt; / template & gt;

& lt; script & gt;
défaut d'exportation {
    Les données() {
        revenir {
            article: ''
        }
    },
    calculé: {
        totalNumberOfCartItems () {
            // Accéder à l'état Vuex
            retourne cette. $ store.getters.totalNumberOfCartItems;
        }
    },
    méthodes: {
        addItemToCart () {
            // Vérifie que le champ de saisie n'est pas vide
            if (this.item! == '') {
                // commettre la mutation additemtocart avec la charge utile
                this. $ store.commit ('addItemToCart', this.item)
            }
        },
        
        check-out() {
            // Assurez-vous que le panier n'est pas vide
            if (this.totalNumberOfCartItems & gt; 0) {
                // créer une demande
                let requestPayload = {cart: this. $ store.state.cart};
                // envoie l'action
                this. $ store.dispatch ('checkout', requestPayload);
            }
            autre {
                alert ('Le panier est vide');
            }
        }
    }
}
& lt; / script & gt;

En fonction du code ci-dessus, nous avons créé un bouton de paiement dans la vue, ainsi qu'une méthode de paiement permettant de vérifier si le panier n'est pas vide avant d'essayer d'envoyer l'action qui envoie les articles.

Cela fonctionne, mais quelque chose est manquant. Vous pourriez vous demander ce que c'est? Nous avons pu envoyer une action, mais nous ne savons pas si cette action a abouti ou non.

L'appel de l'API a-t-il échoué? Est-ce que c'est passé? Comment puis-je obtenir cette information pour pouvoir informer l'utilisateur? Les actions peuvent gérer les promesses et peuvent également renvoyer une promesse.

Modifier notre exemple de code pour renvoyer une promesse:

 // import Vue
importer Vue de 'vue';
// importer Vuex
importer Vuex depuis 'vuex';

// Installer le plugin Vuex sur vue
Vue.use (Vuex);

// créer une instance de magasin Vuex
export const store = new Vuex.Store ({
    Etat: {
        panier: ["bread", "rice", "beans", "turkey"]
    },
  
    getters: {
        // Récupère le nombre total d'articles dans le panier
        totalNumberOfCartItems: state = & gt; {
            return state.cart.length;
        },
    },
    
    mutations: {
        // Ajouter un article au panier
        addItemToCart (état, charge utile) {
            state.cart.push (charge utile);
        },
        // Effacer les articles dans le panier
        emtpyCart (state) {
            state.cart = [];
        }
    },
    
    actes: {
        checkout ({commit}, requestObject) {
            renvoyer une nouvelle promesse ((résoudre, rejeter) = & gt; {
                
                // Appel API pour soumettre les articles dans le panier
                Vue.http.post ('submit', requestObject) .then ((response) = & gt; {
                    // journal des succès
                    console.log (réponse);
                    // Efface le panier en modifiant l'état
                    commit ('emptyCart');
                    // retourne le succès
                    résoudre (réponse);
                }). catch ((error) = & gt; {
                    // erreur de journal
                    console.log (erreur);
                    // retourne une erreur
                    rejeter (erreur);
                }
            })
        }
    }
})

Nous pouvons maintenant utiliser la valeur renvoyée pour mettre à jour l'utilisateur dans l'état de la vue comme suit:

 & lt; modèle & gt;
    & lt; main & gt;
        & lt; h1 & gt; Contenu du panier & lt; / h1 & gt;
        & lt; p & gt; Nombre total d'éléments: {{totalNumberOfCartItems}} & lt; / p & gt;
        & lt; form @ submit.prevent = "addItemToCart" & gt;
            & lt; input type = "text" v-model = "item" requis & gt;
            & lt; button type = "submit" & gt; Ajouter au panier & lt; / button & gt;
        & lt; / form & gt;
        
        & lt; button type = "button" @ click = "checkout" & gt; Commander & lt; / button & gt;
    & lt; / main & gt;
& lt; / template & gt;

& lt; script & gt;
défaut d'exportation {
    Les données() {
        revenir {
            article: ''
        }
    },
    calculé: {
        totalNumberOfCartItems () {
            // Accéder à l'état Vuex
            retourne cette. $ store.getters.totalNumberOfCartItems;
        }
    },
    méthodes: {
        addItemToCart () {
            // Vérifie que le champ de saisie n'est pas vide
            if (this.item! == '') {
                // commettre la mutation additemtocart avec la charge utile
                this. $ store.commit ('addItemToCart', this.item)
            }
        },
        
        check-out() {
            // Assurez-vous que le panier n'est pas vide
            if (this.totalNumberOfCartItems & gt; 0) {
                // créer une demande
                let requestPayload = {cart: this. $ store.state.cart};
                // envoie l'action
                this. $ store.dispatch ('checkout', requestPayload) .then ((response) = & gt; {
                    // Alerte Réponse de l'API
                    alerte (réponse);
                }). catch ((error) = & gt; {
                    // Alerte Erreur de l'API
                    alerte (erreur);
                });
            }
            autre {
                alert ('Le panier est vide');
            }
        }
    }
}
& lt; / script & gt;

Les actions vous permettent également d’envoyer plusieurs actions (c’est-à-dire qu’une action peut envoyer une ou plusieurs autres actions). Tout ce que vous avez à faire est de passer dispatch comme argument et vous pourrez alors envoyer d'autres actions dans votre action.

 checkout ({dispatch, commit}, requestObject) {
    // envoie une action
    dispatch ('actionName');

    // envoie une autre action
    dispatch ('actionName2', demande);
};

Ajout de structure au magasin

À l'heure actuelle, nous avons tous nos états, getters, mutations et actions dans un seul fichier, le fichier store.js. En fonction de la taille de notre base de code, ce fichier peut avoir tendance à devenir très volumineux et il est donc logique que nous le scindions en fichiers séparés.

 store /
- | store.js
- | state.js
- | getters.js
- | mutations.js
- | actions.js

Notre magasin ressemble à ceci:

 importer Vue depuis 'vue'
importer Vuex depuis 'vuex'
état d'importation de './state'
importer des getters './getters'
importer des mutations de './mutations'
importer des actions à partir de './actions'

Vue.use (Vuex)

exporter par défaut le nouveau Vuex.Store ({
  Etat,
  getters,
  des mutations,
  actes
})

Modules

Vuex nous fournit également des modules dans lesquels nous pouvons structurer ou décomposer notre magasin en modules de magasins plus petits. Chaque module aura son propre état, ses getters, ses mutations et ses actions.

Ceci fonctionne en regroupant des états, des getters, des mutations et des actions associés dans un module. C'est surtout utile lorsque nous avons une application à grande échelle et que le magasin est rempli de beaucoup de code.

En refacturant notre magasin dans un module, nous allons créer un fichier appelé cart.js et procéder à détachez tous nos états, mutations et actions dans notre magasin en relation avec le panier, comme ci-dessous:

 // import Vue
importer Vue de 'vue';

défaut d'exportation {
    Etat: {
        panier: ["bread", "rice", "beans", "turkey"]
    },
  
    getters: {
        // Récupère le nombre total d'articles dans le panier
        totalNumberOfCartItems: state = & gt; {
            return state.cart.length;
        },
    },
    
    mutations: {
        // Ajouter un article au panier
        addItemToCart (état, charge utile) {
            state.cart.push (charge utile);
        },
        // Effacer les articles dans le panier
        emtpyCart (state) {
            state.cart = [];
        }
    },
    
    actes: {
        checkout ({commit}, requestObject) {
            renvoyer une nouvelle promesse ((résoudre, rejeter) = & gt; {
                
                // Appel API pour soumettre les articles dans le panier
                Vue.http.post ('submit', requestObject) .then ((response) = & gt; {
                    // journal des succès
                    console.log (réponse);
                    // Efface le panier en modifiant l'état
                    commit ('emptyCart');
                    // retourne le succès
                    résoudre (réponse);
                }). catch ((error) = & gt; {
                    // erreur de journal
                    console.log (erreur);
                    // retourne une erreur
                    rejeter (erreur);
                }
            })
        }
    }
}

Ensuite, nous l'importons et l'enregistrons dans notre magasin principal.

 import Vue de 'vue'
importer Vuex depuis 'vuex'
état d'importation de './state'
importer des getters à partir de './getters'
importer des mutations de './mutations'
importer des actions à partir de './actions'
importer le panier de './modules/cart'

Vue.use (Vuex)

exporter par défaut le nouveau Vuex.Store ({
  Etat,
  getters,
  des mutations,
  actes,
  modules: {
      Chariot
  }
})

Enfin, notre structure de code ressemblerait à ceci:

 store /
- | store.js
- | state.js
- | getters.js
- | mutations.js
- | actions.js
- | modules/
    - | cart.js

Résumé

Vuex crée un magasin constitué d'états, de getters, de mutations et d'actions. Pour mettre à jour ou modifier un état, vous devez commettre une mutation.

Pour effectuer une tâche asynchrone, vous avez besoin d'une action. Des actions sont envoyées qui, en cas de succès, commettent une mutation qui mute un état, mettant ainsi à jour la vue.

 Cycle de vie graphique de Vuex


Pour plus d'informations sur Vue:

Vue? Découvrez Kendo UI pour Vue notre bibliothèque de composants d'interface utilisateur complète qui vous permet de créer rapidement des applications réactives de haute qualité. Il inclut tous les composants dont vous aurez besoin, des grilles et graphiques aux planificateurs et aux cadrans.




Source link