Recherche…


Introduction

Vuex est un modèle de gestion d'état + bibliothèque pour les applications Vue.js. Il sert de magasin centralisé pour tous les composants d'une application, avec des règles garantissant que l'état ne peut être modifié que de manière prévisible. Il s'intègre également à l'extension officielle des outils de développement de Vue pour fournir des fonctionnalités avancées telles que le débogage de voyage temporel sans configuration et l'exportation / importation d'images instantanées.

Qu'est ce que Vuex?

Vuex est un plugin officiel pour Vue.js qui offre une banque de données centralisée à utiliser dans votre application. Il est fortement influencé par l’architecture de l’application Flux qui comporte un flux de données unidirectionnel qui simplifie la conception et le raisonnement des applications.

Dans une application Vuex, le magasin de données contient tous les états des applications partagées . Cet état est modifié par des mutations qui sont effectuées en réponse à une action invoquant un événement de mutation via le répartiteur .

Un exemple du flux de données dans une application Vuex est présenté dans le diagramme ci-dessous. Architecture d'application Vuex Diagramme utilisé sous licence MIT , à l'origine du dépôt officiel Vuex GitHub .

Les composants individuels de l'application Vue.js peuvent accéder à l'objet store pour récupérer des données via des getters , qui sont des fonctions pures renvoyant une copie en lecture seule des données souhaitées.

Les composants peuvent avoir des actions qui sont des fonctions qui modifient la copie des données du composant, puis utilisent le répartiteur pour envoyer un événement de mutation. Cet événement est ensuite géré par le magasin de données qui met à jour l'état si nécessaire.

Les modifications sont alors automatiquement répercutées dans l'application, car tous les composants sont liés de manière réactive au magasin via leurs getters.


Un exemple illustrant l'utilisation de vuex dans un projet de vue.

const state = {
    lastClickTime: null
}

const mutations = {
    updateLastClickTime: (state, payload) => {
      state.lastClickTime = payload
  }
}

const getters = {
  getLastClickTime: state => {
    return new Date(state.lastClickTime)
  }
}

const actions = {
    syncUpdateTime: ({ commit }, payload) => {
    commit("updateLastClickTime", payload)
  },
  asyncUpdateTime: ({ commit }, payload) => {
    setTimeout(() => {
      commit("updateLastClickTime", payload)
    }, Math.random() * 5000)
  }
}

const store = new Vuex.Store({
  state,
  getters,
  mutations,
  actions
})

const { mapActions, mapGetters } = Vuex;

// Vue 
const vm = new Vue({
    el: '#container',
  store,
  computed: {
      ...mapGetters([
        'getLastClickTime'
    ])
  },
  methods: {
      ...mapActions([
        'syncUpdateTime',
      'asyncUpdateTime'
    ]),
    updateTimeSyncTest () {
        this.syncUpdateTime(Date.now())
    },
    updateTimeAsyncTest () {
        this.asyncUpdateTime(Date.now())
    }
  }
})

Et le modèle HTML pour le même:

<div id="container">
  <p>{{ getLastClickTime || "No time selected yet" }}</p>
  <button @click="updateTimeSyncTest">Sync Action test</button>
  <button @click="updateTimeAsyncTest">Async Action test</button>
</div>
  1. Ici, l' état contient la propriété lastClickTime initialisée en tant que null. Cette configuration des valeurs par défaut est importante pour garder les propriétés réactives . Les propriétés non mentionnées dans l'état seront disponibles mais les modifications apportées par la suite ne seraient pas accessibles en utilisant des getters.

  2. Le getter utilisé fournit une propriété calculée qui sera mise à jour chaque fois qu'une mutation met à jour la valeur de la propriété state.

  3. Seules les mutations sont autorisées à modifier l'état et ses propriétés, cela dit, il le fait de manière synchrone uniquement .

  4. Une Action peut être utilisée en cas de mises à jour asynchrones, où l’appel d’API (ici simulé par setTimeout) peut être effectué dans l’action, et après avoir obtenu la réponse à laquelle une mutation peut être validée, pour passer à l’état. .

Pourquoi utiliser Vuex?

Lors de la création d'applications volumineuses telles que les applications à page unique (SPA), qui consistent généralement en de nombreux composants réutilisables, elles peuvent rapidement devenir difficiles à créer et à gérer. Le partage de données et d’états entre ces composants peut également s’effondrer rapidement et devenir difficile à déboguer et à maintenir.

En utilisant un magasin de données d'application centralisé, l'intégralité de l'état de l'application peut être représentée en un seul endroit, ce qui rend l'organisation plus organisée. Grâce à un flux de données unidirectionnel, à des mutations et à un accès aux données des composants uniquement pour les données requises, il devient beaucoup plus facile de raisonner sur le rôle du composant et sur son impact sur l'état de l'application.

Les composants de VueJS sont des entités distinctes et ils ne peuvent pas partager facilement des données entre eux. Pour partager des données sans vuex nous devons emit l' événement avec des données, puis écouter et attraper cet événement avec on .

composant 1

this.$emit('eventWithDataObject', dataObject)

composant 2

this.$on('eventWithDataObject', function (dataObject) {
    console.log(dataObject)
})

Avec vuex installé, nous pouvons simplement accéder à ses données à partir de n'importe quel composant sans avoir à écouter les événements.

this.$store.state.myData

Nous pouvons également modifier les données de manière synchrone avec les mutateurs , utiliser des actions asynchrones et obtenir des données avec des fonctions de lecture .

Les fonctions de lecture peuvent fonctionner comme des fonctions calculées globales. Nous pouvons y accéder à partir de composants:

this.$store.getters.myGetter

Les actions sont des méthodes globales. Nous pouvons les expédier à partir de composants:

this.$store.dispatch('myAction', myDataObject)

Et les mutations sont le seul moyen de changer les données en vuex. Nous pouvons commettre des modifications:

this.$store.commit('myMutation', myDataObject)

Le code de Vuex ressemblerait à ceci

state: {
  myData: {
    key: 'val'
  }
},
getters: {
  myGetter: state => {
     return state.myData.key.length
  }
},
actions: {
  myAction ({ commit }, myDataObject) {
    setTimeout(() => {
      commit('myMutation', myDataObject)
    }, 2000)
  }
},
mutations: {
  myMutation (state, myDataObject) {
    state.myData = myDataObject
  }
}

Comment installer Vuex?

La plupart du temps, vous utiliserez Vuex dans des applications basées sur des composants de plus grande taille, où vous utiliserez probablement un bundler de modules tel que Webpack ou Browserify en conjonction avec Vueify si vous utilisez des fichiers uniques.

Dans ce cas, le moyen le plus simple d'obtenir Vuex est de NPM. Exécutez la commande ci-dessous pour installer Vuex et l'enregistrer dans les dépendances de votre application.

 npm install --save vuex

Assurez-vous de charger le lien Vuex avec votre configuration Vue en plaçant la ligne suivante après votre instruction require('vue') .

Vue.use(require('vuex'))

Vuex est également disponible sur CDN; vous pouvez récupérer la dernière version de cdnjs ici .

Notifications de licenciement automatique

Cet exemple enregistrera dynamiquement un module vuex pour stocker des notifications personnalisées pouvant être automatiquement rejetées.

notifications.js

résoudre vuex store et définir des constantes

//Vuex store previously configured on other side
import _store from 'path/to/store';

//Notification default duration in milliseconds
const defaultDuration = 8000;

//Valid mutation names
const NOTIFICATION_ADDED = 'NOTIFICATION_ADDED';
const NOTIFICATION_DISMISSED = 'NOTIFICATION_DISMISSED';

définir l'état initial de notre module

const state = {
  Notifications: []
}

définir nos modules getters

const getters = {
  //All notifications, we are returning only the raw notification objects
  Notifications: state => state.Notifications.map(n => n.Raw)
}

définir notre module Actions

const actions = {
  //On actions we receive a context object which exposes the 
  //same set of methods/properties on the store instance
  //{commit} is a shorthand for context.commit, this is an 
  //ES2015 feature called argument destructuring
  Add({ commit }, notification) {
    //Get notification duration or use default duration
    let duration = notification.duration || defaultDuration

    //Create a timeout to dismiss notification
    var timeOut = setTimeout(function () {
      //On timeout mutate state to dismiss notification
      commit(NOTIFICATION_DISMISSED, notification);
    }, duration);

    //Mutate state to add new notification, we create a new object 
    //for save original raw notification object and timeout reference
    commit(NOTIFICATION_ADDED, {
      Raw: notification,
      TimeOut: timeOut
    })
  },
  //Here we are using context object directly
  Dismiss(context, notification) {
    //Just pass payload
    context.commit(NOTIFICATION_DISMISSED, notification);
  }
}

définir nos mutations de module

const mutations = {
  //On mutations we receive current state and a payload
  [NOTIFICATION_ADDED](state, notification) {
    state.Notifications.push(notification);
  },
  //remember, current state and payload
  [NOTIFICATION_DISMISSED](state, rawNotification) {
    var i = state.Notifications.map(n => n.Raw).indexOf(rawNotification);
    if (i == -1) {
      return;
    }

    clearTimeout(state.Notifications[i].TimeOut);
    state.Notifications.splice(i, 1);
  }
}

Enregistrez notre module avec un état, des getters, des actions et une mutation définis

_store.registerModule('notifications', {
  state,
  getters,
  actions,
  mutations
});

Usage

composanteA.vue

Ce composant affiche toutes les notifications en tant qu'alertes bootstrap dans le coin supérieur droit de l'écran, permet également de supprimer manuellement chaque notification.

<template>
<transition-group name="notification-list" tag="div" class="top-right">
  <div v-for="alert in alerts" v-bind:key="alert" class="notification alert alert-dismissible" v-bind:class="'alert-'+alert.type">
    <button v-on:click="dismiss(alert)" type="button" class="close" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    <div>
      <div>
        <strong>{{alert.title}}</strong>
      </div>
      <div>
        {{alert.text}}
      </div>
    </div>
  </div>
</transition-group>
</template>

<script>
export default {
  name: 'arc-notifications',
  computed: {
    alerts() {
      //Get all notifications from store
      return this.$store.getters.Notifications;
    }
  },
  methods: {
    //Manually dismiss a notification
    dismiss(alert) {
      this.$store.dispatch('Dismiss', alert);
    }
  }
}
</script>
<style lang="scss" scoped>
$margin: 15px;

.top-right {
    top: $margin;
    right: $margin;
    left: auto;
    width: 300px;
    //height: 600px;
    position: absolute;
    opacity: 0.95;
    z-index: 100;
    display: flex;
    flex-wrap: wrap;
    //background-color: red;
}
.notification {
    transition: all 0.8s;
    display: flex;
    width: 100%;
    position: relative;
    margin-bottom: 10px;
    .close {
        position: absolute;
        right: 10px;
        top: 5px;
    }

    > div {
        position: relative;
        display: inline;
    }
}
.notification:last-child {
    margin-bottom: 0;
}
.notification-list-enter,
.notification-list-leave-active {
    opacity: 0;
    transform: translateX(-90px);
}
.notification-list-leave-active {
    position: absolute;
}
</style>

Extrait de code pour ajouter une notification dans tout autre composant

//payload could be anything, this example content matches with componentA.vue 
this.$store.dispatch('Add', {
  title = 'Hello',
  text = 'World',
  type = 'info',
  duration = 15000
});


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow