Le applicazioni frontend, soprattutto quelle più complesse, devono elaborare molti dati. I programmatori introducono vari modelli di progettazione per rendere i loro progetti leggibili e manutenibili. Nella maggior parte degli scenari comuni di un MVC, vogliamo separare i dati dalle parti visive dell'applicazione.
Questo è il motivo per cui negozio è diventato così utile. Sta a voi scegliere se utilizzare React + Redux o Vue + Vuex - l'obiettivo principale è lo stesso, vale a dire mantenere i dati strutturati, accessibili e sicuri allo stesso tempo.
In questo articolo, vi mostrerò alcuni esempi di come mantenere il vostro negozio Vuex pulito ed efficiente.
Prima di iniziare, ipotizziamo che:
- avete un po' di esperienza con il moderno JavaScript,
- sapete fondamentalmente che cos'è l'Vue e come si usa puntelli, calcolato, ecc,
- avete familiarità con l'Vuex (azioni, mutazioni, ecc.) e volete migliorare le vostre applicazioni.
Vuexcome la maggior parte dei core Progetti Vueè abbastanza ben documentato e nei documenti ufficiali si possono trovare molti suggerimenti utili. Abbiamo estratto per voi alcune informazioni essenziali.
Un'implementazione di base del negozio Vuex si presenta come segue:
// main.js
importare Vue da 'vue'
importare Vuex da 'vuex'
importare App da "./App";
Vue.use(Vuex)
const store = new Vuex.Store((
stato: (
dati: null;
),
azioni: (
someAction: (( commit ), data) (
commit("SOME_MUTATION", dati);
)
),
mutazioni: (
SOME_MUTATION (stato, dati) (
stato.dati = dati;
)
))
));
nuovo Vue((
el: "#app",
render: h => h(App),
negozio
));
Di solito, quando l'applicazione diventa più grande, è necessario applicare il routing, alcune direttive globali, i plugin, ecc. Questo rende il main.js
molto più lungo e difficile da leggere. È buona norma conservare l'archivio in un file esterno, come qui:
// store.js
importare Vue da 'vue'
importare Vuex da 'vuex'
Vue.use(Vuex);
const state = (
dati: null;
);
const azioni = (
someAction: (( commit ), data) (
commit("SOME_MUTATION", dati);
)
);
mutazioni = (
SOME_MUTATION (stato, dati) (
stato.dati = dati;
)
);
esportazione predefinita nuovo Vuex.Store((
stato,
azioni,
mutazioni
));
1. I moduli
Cosa fare quando il store.js
file diventa enorme e difficile da lavorare? In realtà, c'è una caratteristica davvero interessante dell'Vuex - moduli. Sono dedicati alla suddivisione dei dati in file separati.
Immaginate di lavorare su un'applicazione aziendale, in cui avete pochi domini di dati, ad esempio:
- utente (gestisce tutte le autorizzazioni e i permessi),
- parametri del percorso (gestire i parametri globali prima delle richieste all'API),
- vendite (per il componente SalesMegaChart visibile in un contesto mensile/trimestrale/annuale),
- ordini (visibile dopo aver fatto clic sulla barra SalesMegaChart).
... e forse qualche altro. Ora avete seri motivi per introdurre un po' di modularità nel vostro negozio.
Prima di tutto, spostate il store.js
in un file appena creato negozio/
e rinominarla index.js
. Facoltativamente, se si vuole mantenere tutto in moduli, si può rimuovere il file Stato, azioni e mutazioni dal file principale.
// store/index.js
importare Vue da 'vue'
importare Vuex da 'vuex'
Vue.use(Vuex);
export default new Vuex.Store((
moduli: (
// i moduli andranno qui
)
));
Quindi, accanto al file `store/index.js`, creare il primo modulo - `store/user.js`.
import ApiService da '../services/api.service';
const state = (
loggedIn: false,
loginError: null,
utente: null
);
const azioni = (
login: async (( commit ), data) (
try (
const response = await ApiService.post('/login', data);
const ( user ) = response.data;
COMMIT("SAVE_USER", user);
COMMIT("LOGIN_SUCCESS");
) catch (error) (
commit("LOGIN_ERROR", errore);
)
)
);
mutazioni = (
SAVE_USER (stato, utente) (
stato.utente = utente;
),
LOGIN_SUCCESS (stato) (
state.loggedIn = true;
),
LOGIN_ERROR (stato, errore) (
state.loginError = error;
state.loggedIn = false;
)
);
esportare const utente (
stato,
azioni,
mutazioni
)
E ora, caricare il modulo pronto nel file principale `store/index.js`:
import Vue da 'vue'
importare Vuex da 'vuex'
import ( user ) da './user';
Vue.use(Vuex);
export default new Vuex.Store((
moduli: (
utente
)
));
Congratulazioni! Ora avete un'implementazione del negozio davvero bella. Si può anche accedere ai dati dal componente (p.e, Profilo utente.vue
) in questo modo:
<template>
<div class="user-profile">
<h2>(( user.name ))!</h2>
<!-- component template goes here -->
</div>
</template>
<script> import ( mapActions ) from 'Vuex';
export default (
name: 'UserProfile',
computed: mapState((
user: state => state.user
// user: 'user' <-- alternative syntax
))
)
</script>
2. Spazi dei nomi
Ora che si sa come utilizzare i moduli, è necessario acquisire familiarità con le funzioni dell'Vuex. spaziatura dei nomi. Nel passo precedente, abbiamo creato il file store/user.js
con il file utente modulo.
La struttura dei dati definita nel file utente.js
è accessibile dai componenti, ma è possibile notare che tutti i file utente i dati vengono trasmessi direttamente al sistema globale Stato
contesto, come in questo caso:
calcolato: mapState((
utente: stato => stato.utente
// utente: 'utente' <-- modo alternativo
))
Quando si definiscono più moduli, probabilmente ci si confonde su quale oggetto provenga da quale modulo. Quindi si dovrebbero usare moduli con spazi per i nomi e definirli in questo modo:
esportare const utente (
namespaced: true, // <-- namespacing!
stato,
azioni,
mutazioni
)
D'ora in poi, tutti i vostri utente dati (Stato
variabile da store/user.js
) saranno gestiti nell'ambito del file stato.utente
riferimento:
calcolato: mapState((
utente: stato => stato.utente.utente
// utente: 'user/user' <-- modo alternativo
))
Qualche passo dopo, si può ottenere per il componente qualcosa di simile:
import ( mapActions ) da 'Vuex';
esportare default (
nome: 'Dashboard',
calcolato: mapState((
vendite: 'vendite/dati',
ordini: 'ordini/dati',
sortBy: 'orders/sortBy',
loggedIn: 'utente/loggedIn'
)),
metodi: mapActions((
logout: 'user/logout',
loadSales: 'sales/load',
caricoOrdini: 'ordini/carico'
)),
creato() (
se (this.loggedIn) (
loadSales();
caricareOrdini();
)
)
)
Bravi! Così fresco, così pulito... Ma non preoccupatevi, il refactoring non finisce mai. Pronti per i prossimi passi?
3. Comunicazione tra moduli
Nel primo passo, ho mostrato un'azione nel utente modulo:
const azioni = (
login: async (( commit ), data) (
try (
const response = await ApiService.post('/login', data);
const ( user ) = response.data;
COMMIT("SAVE_USER", user);
COMMIT("LOGIN_SUCCESS");
) catch (error) (
commit("LOGIN_ERROR", errore);
)
)
);
In caso di fallimento, stiamo aggiungendo l'errore di login al nostro negozio: qual è il prossimo passo?
Qui abbiamo alcune opzioni e la scelta dipende da quale opzione si adatta meglio alle vostre esigenze. Il modo più semplice è quello di utilizzare il metodo v-if
grazie alla quale è possibile visualizzare un messaggio di errore in caso di errore nel negozio.
<template>
<div class="dashboard">
<!-- dashboard component template -->
<div
v-if="error"
class="error-message"
> (( error.message )) </div>
</div>
</template>
<script> import ( mapActions ) from 'Vuex';
export default (
name: 'Dashboard',
computed: mapState((
error: "user/loginError"
))
)
</script>
Di nuovo, immaginiamo di avere molti moduli e ognuno di essi try/catch
genera un nuovo errore nel negozio. Ovviamente, in questo modo si abusa della regola DRY.
Come si possono rendere più generici i processi di gestione degli errori?
Definiamo il parametro comune e inserirvi una logica da utilizzare a livello globale.
// store/common.js
const state = (
errori: []
);
const azioni = (
errore: (
root: true,
handler(( commit ), error) (
commit("ERROR", errore);
)
)
),
mutazioni = (
ERRORE (stato, errore) (
/* in questo modo avremo l'errore più recente in cima alla lista */
state.errors = [error, ...state.errors];
))
);
esportare la const comune (
namespaced: true,
stato,
mutazioni
)
Ora, possiamo adattare il metodo utente (e anche altri moduli):
try (
// qualche azione
)catch (error) (
commit("common/ERROR", error, ( root: true ));
)
oppure, in modo più elegante, utilizzando la nostra azione globale:
try (
// qualche azione
) catch (error) (
dispatch("errore", errore);
)
Questa sintassi di impegnarsi
e spedizione
Le chiamate sembrano autoesplicative, ma è possibile saperne di più su questi trucchi qui.
Quando si hanno tutti gli errori in un unico posto, è possibile caricarli facilmente nella propria cartella di lavoro. Cruscotto
componente:
calcolato: mapState((
errori: 'common/errors'
)),
watch: (
/* questo verrà invocato dopo ogni mutazione "common/ERROR", in cui si aggiungono solo nuovi errori all'archivio, uno alla volta */
errori() (
this.showErrorMessage(this.errors[0]);
)
)
L'esempio precedente con l'opzione comune La gestione degli errori del modulo è già una soluzione efficiente, ma si può andare oltre.
Come si può vedere, stiamo osservando i cambiamenti sul comune/errori
nell'archivio. In casi come questi, quando è necessario determinare un'azione su una particolare mutazione, si può usare Plugin Vuex o addirittura componenti di ordine superiore (HOC).
Discuterò i plugin e gli HOC nel prossimo articolo. Nel frattempo, vi ringrazio per aver letto questo articolo e spero che abbiate apprezzato gli esempi che abbiamo preparato.
Restate sintonizzati e continuate a codificare!
Per saperne di più:
– Come migliorare le applicazioni Vue.js? Alcuni consigli pratici
– GraphQL: lezioni apprese in produzione
– Shopify, Spree o Solidus? Scoprite perché Ruby on Rails può aiutarvi a sviluppare il vostro e-commerce.