Come passare i dati tra i componenti in Vue.js

Pubblicato: 2022-03-10
Riepilogo rapido ↬ Con così tanti modi diversi per condividere i dati tra i componenti, dovresti sapere quale tecnica è la migliore per la tua situazione. Analizziamo tre dei modi più comuni per passare i dati in VueJS.

La condivisione dei dati tra i componenti è una delle funzionalità principali di VueJS. Ti consente di progettare un progetto più modulare, controllare gli ambiti dei dati e creare un flusso naturale di dati nell'app.

A meno che tu non stia creando l'intera app Vue in un componente (il che non avrebbe alcun senso), incontrerai situazioni in cui devi condividere i dati tra i componenti.

Alla fine di questo tutorial, conoscerai tre modi per farlo.

  • Usando gli oggetti di scena per condividere i dati da genitore a figlio,
  • Emissione di eventi personalizzati per condividere dati da figlio a genitore,
  • Utilizzo di Vuex per creare uno stato condiviso a livello di app.

Va bene — entriamo subito!

Costruire un'app con Nuxt

Con Spotify, i tuoi amici possono controllare a cosa stai suonando. E se anche il resto di Internet potesse sperimentare il tuo algoritmo? Scopri come comporre la tua app per condividere ciò che stai ascoltando su Spotify utilizzando Vue.js e Nuxt. Leggi un articolo correlato →

Altro dopo il salto! Continua a leggere sotto ↓

1. Utilizzo di oggetti di scena per condividere i dati da genitore a figlio

Gli oggetti di scena VueJS sono il modo più semplice per condividere i dati tra i componenti. Gli oggetti di scena sono attributi personalizzati che possiamo assegnare a un componente. Quindi, nel nostro modello, possiamo dare a quegli attributi valori e — BAM — stiamo passando i dati da un genitore a un componente figlio!

Ad esempio, supponiamo che stiamo lavorando su una pagina del profilo utente e desideriamo che un componente figlio accetti un nome utente prop. Avremo bisogno di due componenti.

  1. Il componente figlio che accetta l'oggetto di scena, chiamiamo questo AccountInfo.vue .
  2. Il componente padre che passa il prop, chiamiamo questo ProfilePage.vue .

All'interno AccountInfo.vue , possiamo dichiarare gli oggetti di scena che accetta utilizzando l'opzione oggetti di scena. Quindi, all'interno delle opzioni del componente, facciamo in modo che assomigli al seguente.

 // AccountInfo.vue <template> <div id='account-info'> {{username}} </div> </template> <script> export default { props: ['username'] } </script>

Quindi, per passare effettivamente i dati dal genitore ( ProfilePage.vue ), lo passiamo come un attributo personalizzato.

 // ProfilePage.vue <account-info username='matt' />

Ora, se carichiamo la nostra pagina, possiamo vedere che il nostro componente AccountInfo rende correttamente il valore passato dal suo genitore.

Come quando si lavora con altre direttive VueJS, possiamo usare v-bind per passare dinamicamente gli oggetti di scena. Ad esempio, supponiamo di voler impostare il prop nome utente in modo che sia uguale a una variabile. Possiamo farlo usando la scorciatoia per la direttiva v-bind (o semplicemente : in breve). Il codice sarebbe un po' così:

 <template> <div> <account-info :username="user.username" /> </div> </template> <script> import AccountInfo from "@/components/AccountInfo.vue"; export default { components: { AccountInfo }, data() { return { user: { username: 'matt' } } } } </script>

Ciò significa che possiamo modificare i nostri dati e fare in modo che anche gli oggetti di scena per bambini che utilizzano quel valore si aggiorneranno.

Suggerimento: verifica sempre i tuoi oggetti di scena

Se stai cercando di scrivere un codice Vue più chiaro, una tecnica importante è verificare i tuoi oggetti di scena. In breve, questo significa che devi specificare i requisiti per il tuo oggetto di scena (es. tipo, formato e così via). Se uno di questi requisiti non è soddisfatto (ad es. se l'elica è di tipo errato), Vue stamperà un avviso.

Diciamo che vogliamo che il nostro nome utente prop accetti solo stringhe. Dovremmo modificare il nostro oggetto props in modo che assomigli a questo:

 export default { props: { username: String } }

La verifica degli oggetti di scena è essenziale quando si lavora in app Vue su larga scala o durante la progettazione di plug-in. Aiuta a garantire che tutti siano sulla stessa pagina e a utilizzare gli oggetti di scena nel modo in cui erano destinati.

Per un elenco completo delle verifiche che possiamo includere sugli oggetti di scena, consiglio vivamente di controllare la documentazione ufficiale per una revisione approfondita.

Suggerimento: segui le convenzioni di denominazione degli oggetti di scena

Secondo la guida di stile VueJS, il modo migliore per dare un nome ai tuoi oggetti di scena è usare camelCase quando li dichiari nel tuo script e kebab-case quando li fai riferimento nel codice del modello.

Il ragionamento alla base di questo è in realtà abbastanza semplice. In Javascript, camelCase è la convenzione di denominazione standard e in HTML è kebab-case.

Quindi, Vue raccomanda di attenerci alle norme di ciascuna lingua. Per fortuna, Vue è in grado di convertire automaticamente tra i due stili, quindi non ci sono impostazioni aggiuntive per gli sviluppatori.

 // GOOD <account-info :my-username="user.username" /> props: { myUsername: String } // BAD <account-info :myUsername="user.username" /> props: { "my-username": String }

2. Emissione di eventi per condividere dati da bambino a genitore

Ora che abbiamo i dati che passano lungo la gerarchia, passiamoli nell'altro modo: da un componente figlio a un genitore. Non possiamo usare oggetti di scena, ma possiamo usare eventi e listener personalizzati.

Ogni istanza di Vue può chiamare un metodo .$emit(eventName) che attiva un evento. Quindi, possiamo ascoltare questo evento allo stesso modo di qualsiasi altro, usando la direttiva v-on.

Creazione di un evento personalizzato

Utilizziamo il nostro esempio di profilo utente aggiungendo un pulsante che cambia il nome utente. All'interno del nostro componente figlio ( AccountInfo.vue ), creiamo il pulsante.

Quindi, quando si fa clic su questo pulsante, verrà generato un evento chiamato changeUsername .

 <template> <div id='account-info'> <button @click='changeUsername()'>Change Username</button> {{username}} </div> </template> <script> export default { props: { username: String }, methods: { changeUsername() { this.$emit('changeUsername') } } } </script>

All'interno del genitore, gestiamo questo evento e cambiamo la variabile user.username . Come abbiamo discusso in precedenza, possiamo ascoltare gli eventi usando la direttiva v-on o "@" in breve.

 <template> <div> <account-info :username="user.username" @changeUsername="user.username = 'new name'"/> </div> </template>

Proviamolo. Dovresti vedere che quando fai clic sul pulsante, il nome utente cambia in "nuovo nome".

Suggerimento: gli eventi personalizzati possono accettare argomenti

Il caso d'uso più comune per passare argomenti ai tuoi eventi è quando vuoi che un componente figlio sia in grado di impostare un valore specifico per il suo prop. Non vuoi mai modificare direttamente il valore di un oggetto di scena dal componente stesso.

Tuttavia, fortunatamente possiamo usare gli argomenti pass con i nostri eventi personalizzati per fare in modo che il componente genitore modifichi i valori.

Supponiamo di voler modificare l'evento changeUsername in modo da potergli passare un valore.

Il metodo $emit accetta un secondo parametro facoltativo per gli argomenti. Quindi tutto ciò che facciamo è aggiungere il nostro nuovo valore per il nome utente dopo il nome del nostro evento.

 this.$emit('changeUsername', 'mattmaribojoc')

Quindi, nel nostro componente padre, possiamo accedere a questi valori in linea utilizzando una speciale variabile $event , oppure possiamo scrivere un metodo di gestione che accetta un parametro.

 <account-info :username="user.username" @changeUsername="user.username = $event"/> OR <account-info :username="user.username" @changeUsername="changeUsername($event)"/> export default { ... methods: { changeUsername (username) { this.user.username = username; } } }

3. Utilizzo di Vuex per creare uno stato condiviso a livello di applicazione

Ok, sappiamo come condividere i dati tra genitori/figli, ma per quanto riguarda gli altri componenti? Dobbiamo creare un sistema gerarchico estremamente complesso se vogliamo passare i dati?

Per fortuna no. La meravigliosa libreria di gestione dello stato Vuex semplifica da anni la vita degli sviluppatori. In breve, crea un archivio dati centralizzato accessibile da tutti i componenti.

Nei metodi che abbiamo usato in precedenza (props/emitting events), ogni componente ha il proprio stato di dati che poi condividiamo tra i componenti. Tuttavia, Vuex ci consente di estrarre tutti i dati condivisi in un unico stato a cui ogni componente può accedere facilmente. Questo stato condiviso è chiamato negozio.

Proviamolo.

Poiché Vuex è separato dal codice principale di Vue, dovremo prima installarlo e importarlo nel nostro progetto. Innanzitutto, dovremo eseguire npm install vuex --save all'interno della CLI del nostro progetto.

Quindi, crea una cartella src/store con un file index.js che contiene il codice seguente.

 // store/index.js import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export default new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {} });

Per includerlo nella nostra istanza principale di Vue, dobbiamo importare il nostro file store/index.js e passarlo nel nostro costruttore Vue.

 // main.js import store from "./store"; new Vue({ store, ...

Accesso a Vue Store all'interno dei componenti

Dal momento che abbiamo aggiunto il nostro negozio Vuex alla nostra istanza di root Vue, viene iniettato in tutti i figli della radice. Se vogliamo accedere al negozio da un componente, possiamo tramite this.$store .

Ora, tuffiamoci nei dettagli di ciascuna delle quattro parti di un negozio Vuec.

1. Stato

Lo stato Vuex è un oggetto che contiene dati a livello di applicazione. Tutte le istanze Vue potranno accedere a questi dati.

Per il nostro negozio, creiamo un oggetto utente che memorizza alcuni dati del profilo utente in più.

 export default new Vuex.Store({ state: { user: { username: 'matt', fullName: 'Matt Maribojoc' } }, getters: {}, mutations: {}, actions: {} });

Possiamo accedere a questi dati all'interno di qualsiasi componente di istanza come questo.

 mounted () { console.log(this.$store.state.user.username); },

2. Gettatori

Usiamo i getter Vuex per restituire un valore modificato dei dati di stato. Un buon modo per pensare ai getter è trattarli come proprietà calcolate. Ad esempio, i getter, come le proprietà calcolate, memorizzano nella cache i risultati e rivalutano solo quando viene modificata una dipendenza.

Basandosi sul nostro negozio precedente, supponiamo di voler creare un metodo che restituisca il nome di un utente in base all'attributo del nome completo.

 getters: { firstName: state => { return state.user.fullName.split(' ')[0] } }

Le proprietà getter Vuex sono disponibili per i componenti dell'oggetto store.getters .

 mounted () { console.log(this.$store.getters.firstName); }

Suggerimento: conosci gli argomenti Getter predefiniti

Per impostazione predefinita, i getter Vuex accettano due argomenti.

  1. stato — l'oggetto stato per la nostra applicazione;
  2. getters — l'oggetto store.getters, il che significa che possiamo chiamare altri getter nel nostro negozio.

Ogni getter che dichiari richiederà il primo argomento di stato. E a seconda di come progetti il ​​tuo codice, i tuoi getter possono fare riferimento a vicenda usando il secondo argomento "getter".

Facciamo un getter del cognome che rimuove semplicemente il valore del nostro nome dalla nostra proprietà dello stato del nome completo. Questo esempio richiederebbe sia gli oggetti state che getters.

 lastName (state, getters) { return state.user.fullName.replace(getters.firstName, ''); }

Suggerimento: passa argomenti personalizzati a Vuex Getter

Un'altra caratteristica interessante dei getter è che possiamo passare loro argomenti personalizzati facendo in modo che il nostro getter restituisca un metodo.

 prefixedName: (state, getters) => (prefix) => { return prefix + getters.lastName; } // in our component console.log(this.$store.getters.prefixedName("Mr."));

3. Mutazioni

Le mutazioni sono l' unico modo per modificare correttamente il valore dell'oggetto di stato. Un dettaglio importante da notare è che le mutazioni devono essere sincrone .

Come i getter, le mutazioni accettano sempre la proprietà dello stato Vuex come primo argomento. Accettano anche un argomento personalizzato, chiamato payload, come secondo argomento.

Ad esempio, eseguiamo una mutazione per modificare il nome di un utente in un valore specifico.

 mutations: { changeName (state, payload) { state.user.fullName = payload } },

Quindi, possiamo chiamare questo metodo dal nostro componente usando il metodo store.commit , con il nostro payload come secondo argomento.

 this.$store.commit("changeName", "New Name");

Il più delle volte, vorrai che il tuo carico utile sia un oggetto. Questo non solo significa che puoi passare diversi argomenti a una mutazione, ma rende anche il tuo codice più leggibile grazie ai nomi delle proprietà nel tuo oggetto.

 changeName (state, payload) { state.user.fullName = payload.newName }

Esistono due modi diversi per chiamare le mutazioni con un carico utile.

  1. Puoi avere il tipo di mutazione come primo argomento e il carico utile come secondo.
  2. Puoi dichiarare di passare un singolo oggetto, con una proprietà per il tipo e un'altra per il payload.
 this.$store.commit("changeName", { newName: "New Name 1", }); // or this.$store.commit({ type: "changeName", newName: "New Name 2" });

Non c'è una vera differenza tra il modo in cui funzionano i due, quindi dipende totalmente dalle preferenze personali. Ricorda che è sempre meglio essere coerenti durante l'intero progetto, quindi qualunque cosa tu scelga, mantienila!

4. Azioni

In Vuex, le azioni sono abbastanza simili alle mutazioni perché le usiamo per cambiare lo stato. Tuttavia, le azioni non cambiano i valori stessi. Invece, le azioni commettono mutazioni.

Inoltre, mentre le mutazioni Vuex devono essere sincrone, le azioni no. Usando le azioni, ad esempio, possiamo chiamare una mutazione dopo una chiamata API.

Mentre la maggior parte dei gestori Vuex che abbiamo visto accettano lo stato come parametro principale, le azioni accettano un oggetto di contesto. Questo oggetto di contesto ci consente di accedere alle proprietà nel nostro negozio Vuex (es. stato, commit, getter).

Ecco un esempio di un'azione Vuex che attende due secondi e quindi esegue il commit della mutazione changeName .

 actions: { changeName (context, payload) { setTimeout(() => { context.commit("changeName", payload); }, 2000); } }

All'interno dei nostri componenti, utilizziamo il metodo store.dispatch per eseguire la nostra funzione. Passiamo argomenti proprio come abbiamo fatto con le mutazioni. Dichiariamo il tipo e passiamo eventuali argomenti personalizzati nel secondo argomento.

 this.$store.dispatch("changeName", { newName: "New Name from Action" });

Avvolgendo

Ora dovresti conoscere tre modi diversi per condividere i dati tra i componenti in VueJS: oggetti di scena, eventi personalizzati e un negozio Vuex.

Spero che questo tutorial ti abbia aiutato a darti un'idea in più di alcuni diversi metodi e migliori pratiche Vue. Fammi sapere come li hai implementati nei tuoi progetti!

Ulteriori letture

Se sei interessato ad approfondire ulteriormente il lato/le capacità tecniche di ciascuna tecnica, ecco alcuni ottimi punti di partenza.

  • Sito della Guida Ufficiale Vuex
  • Documenti VueJS per oggetti di scena ed eventi personalizzati
  • "WTF è Vuex? Una guida per principianti all'Application Data Store di Vue", Anthony Gore, sviluppatori Vue.js