Cum să transferați date între componente în Vue.js

Publicat: 2022-03-10
Rezumat rapid ↬ Cu atât de multe moduri diferite de a partaja date între componente, ar trebui să știți care tehnică este cea mai bună pentru situația dvs. Să analizăm trei dintre cele mai comune moduri de a transmite date în VueJS.

Partajarea datelor între componente este una dintre funcționalitățile de bază ale VueJS. Vă permite să proiectați un proiect mai modular, să controlați sfera datelor și să creați un flux natural de date în aplicația dvs.

Dacă nu vă creați întreaga aplicație Vue într-o singură componentă (ceea ce nu ar avea niciun sens), veți întâlni situații în care trebuie să partajați date între componente.

Până la sfârșitul acestui tutorial, veți cunoaște trei modalități de a realiza acest lucru.

  • Folosind elemente de recuzită pentru a partaja date de la părinte la copil,
  • Emiterea de evenimente personalizate pentru a partaja date de la copil la părinte,
  • Folosind Vuex pentru a crea o stare partajată la nivel de aplicație.

Bine, hai să intrăm direct în asta!

Crearea unei aplicații cu Nuxt

Cu Spotify, prietenii tăi pot vedea la ce te bruiezi. Ce se întâmplă dacă și restul internetului ar putea experimenta algo-ritmul tău? Aflați cum să compuneți propria aplicație pentru a partaja ceea ce ascultați pe Spotify folosind Vue.js și Nuxt. Citiți un articol înrudit →

Mai multe după săritură! Continuați să citiți mai jos ↓

1. Utilizarea elementelor de recuzită pentru a partaja date de la părinte la copil

Recuzitele VueJS sunt cel mai simplu mod de a partaja date între componente. Recuzitele sunt atribute personalizate pe care le putem da unei componente. Apoi, în șablonul nostru, putem da acele atribute valori și — BAM — transmitem date de la o componentă părinte la o componentă copil!

De exemplu, să presupunem că lucrăm la o pagină de profil de utilizator și dorim ca o componentă copil să accepte un nume de utilizator prop. Vom avea nevoie de două componente.

  1. Componenta copil care acceptă prop, să numim acest AccountInfo.vue .
  2. Componenta părinte care trece prop, să numim această ProfilePage.vue .

În interiorul AccountInfo.vue , putem declara elementele de recuzită pe care le acceptă folosind opțiunea props. Deci, în interiorul opțiunilor componente, să-l facem să arate ca următorul.

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

Apoi, pentru a transmite efectiv datele de la părinte ( ProfilePage.vue ), le transmitem ca pe un atribut personalizat.

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

Acum, dacă încărcăm pagina noastră, putem vedea că componenta noastră AccountInfo redă corect valoarea transmisă de părintele ei.

La fel ca atunci când lucrăm cu alte directive VueJS, putem folosi v-bind pentru a transmite în mod dinamic elementele de recuzită. De exemplu, să presupunem că vrem să setăm prop numele de utilizator să fie egal cu o variabilă. Putem realiza acest lucru folosind prescurtarea pentru directiva v-bind (sau doar : pe scurt). Codul ar arăta puțin așa:

 <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>

Aceasta înseamnă că ne putem schimba datele și că orice obiect de recuzită pentru copii care utilizează acea valoare se va actualiza și el.

Sfat: verificați întotdeauna elementele de recuzită

Dacă doriți să scrieți un cod Vue mai clar, o tehnică importantă este să vă verificați recuzita. Pe scurt, aceasta înseamnă că trebuie să specificați cerințele pentru recuzita dvs. (adică tipul, formatul și așa mai departe). Dacă una dintre aceste cerințe nu este îndeplinită (de exemplu, dacă recuzita este trecută cu un tip incorect), Vue va imprima un avertisment.

Să presupunem că vrem ca prop numele nostru de utilizator să accepte doar șiruri. Ar trebui să ne modificăm obiectul de recuzită pentru a arăta astfel:

 export default { props: { username: String } }

Verificarea elementelor de recuzită este esențială atunci când lucrați în aplicații Vue la scară largă sau când proiectați pluginuri. Vă ajută să vă asigurați că toată lumea este pe aceeași pagină și că folosește recuzita așa cum au fost destinate.

Pentru o listă completă a verificărilor pe care le putem include la recuzită, aș recomanda cu siguranță să consultați documentația oficială pentru o revizuire aprofundată.

Sfat: Urmați convențiile de denumire a prop

Conform ghidului de stil VueJS, cel mai bun mod de a vă numi elementele de recuzită este să utilizați camelCase atunci când le declarați în script și kebab-case atunci când faceți referire la ele în codul șablonului.

Raționamentul din spatele acestui lucru este de fapt destul de simplu. În Javascript, camelCase este convenția standard de denumire, iar în HTML, este kebab-case.

Așadar, Vue recomandă să respectăm normele fiecărei limbi. Din fericire, Vue poate face conversia automată între cele două stiluri, astfel încât nu există o configurare suplimentară pentru dezvoltatori.

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

2. Emiterea de evenimente pentru a partaja date de la copil la părinte

Acum că avem date care trec în jos în ierarhie, să le transmitem în alt mod: de la o componentă copil la un părinte. Nu putem folosi elemente de recuzită, dar putem folosi evenimente personalizate și ascultători.

Fiecare instanță Vue poate apela o metodă .$emit(eventName) care declanșează un eveniment. Apoi, putem asculta acest eveniment la fel ca oricare altul, folosind directiva v-on.

Crearea unui eveniment personalizat

Să ne bazăm pe exemplul nostru de profil de utilizator adăugând un buton care schimbă numele de utilizator. În interiorul componentei noastre copil ( AccountInfo.vue ), să creăm butonul.

Apoi, când se face clic pe acest buton, vom emite un eveniment numit 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>

În interiorul părintelui, gestionăm acest eveniment și modificăm variabila user.username . Așa cum discutam mai devreme, putem asculta evenimente folosind directiva v-on sau „@” pe scurt.

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

Să-l încercăm. Ar trebui să vedeți că atunci când faceți clic pe butonul, numele de utilizator se schimbă în „nume nou”.

Sfat: evenimentele personalizate pot accepta argumente

Cel mai obișnuit caz de utilizare pentru transmiterea de argumente la evenimentele dvs. este atunci când doriți ca o componentă copil să poată seta o anumită valoare pentru prop. Nu doriți să editați în mod direct valoarea unei elemente de recuzită din componenta în sine.

Cu toate acestea, din fericire, putem folosi argumente de trecere cu evenimentele noastre personalizate pentru a face ca componenta părinte să schimbe valorile.

Să presupunem că vrem să modificăm evenimentul changeUsername astfel încât să îi putem transmite o valoare.

Metoda $emit preia un al doilea parametru opțional pentru argumente. Deci tot ce facem este să adăugăm noua noastră valoare de nume de utilizator după numele evenimentului nostru.

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

Apoi, în componenta noastră părinte, putem fie să accesăm aceste valori în linie folosind o variabilă specială $event , fie putem scrie o metodă de gestionare care preia un parametru.

 <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. Utilizarea Vuex pentru a crea o stare partajată la nivel de aplicație

Bine — știm cum să împărtășim date între părinți/copii, dar cum rămâne cu celelalte componente? Trebuie să creăm un sistem de ierarhie extrem de complex dacă vrem să transmitem date?

Din fericire nu. Minunata bibliotecă de management de stat Vuex simplifică viața dezvoltatorilor de ani de zile. Pe scurt, creează un depozit de date centralizat care este accesibil de către toate componentele.

În metodele pe care le-am folosit anterior (recuzită/emiterea de evenimente), fiecare componentă are propria stare de date pe care apoi o împărtășim între componente. Cu toate acestea, Vuex ne permite să extragem toate datele partajate într-o singură stare pe care fiecare componentă o poate accesa cu ușurință. Această stare partajată se numește magazin.

Să-l încercăm.

Deoarece Vuex este separat de codul de bază al Vue, mai întâi va trebui să îl instalăm și să îl importam în proiectul nostru. Mai întâi, va trebui să rulăm npm install vuex --save în interiorul CLI al proiectului nostru.

Apoi, creați un folder src/store cu un fișier index.js care conține următorul cod.

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

Pentru a include acest lucru în instanța noastră rădăcină Vue, trebuie să importam fișierul store/index.js și să-l transmitem în constructorul nostru Vue.

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

Accesarea Vue Store Inside Components

Deoarece am adăugat magazinul nostru Vuex pe instanța noastră rădăcină Vue, acesta este injectat în toți copiii rădăcinii. Dacă vrem să accesăm magazinul dintr-o componentă, putem prin this.$store .

Acum, să ne aprofundăm în specificul fiecăreia dintre cele patru părți ale unui magazin Vuec.

1. Stat

Starea Vuex este un obiect care conține date la nivel de aplicație. Toate instanțele Vue vor putea accesa aceste date.

Pentru magazinul nostru, să creăm un obiect utilizator care stochează mai multe date de profil de utilizator.

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

Putem accesa aceste date în orice componentă de instanță ca aceasta.

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

2. Getters

Folosim gettere Vuex pentru a returna o valoare modificată a datelor de stare. O modalitate bună de a te gândi la getters este să le tratezi ca pe niște proprietăți calculate. De exemplu, getters, cum ar fi proprietățile calculate, își memorează în cache rezultatele și reevaluează doar atunci când o dependență este modificată.

Bazându-ne pe magazinul nostru anterior, să presupunem că vrem să facem o metodă care returnează prenumele unui utilizator pe baza atributului numelui complet.

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

Proprietățile getter Vuex sunt disponibile componentelor din obiectul store.getters .

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

Sfat: cunoașteți argumentele implicite ale Getter

În mod implicit, getters Vuex acceptă două argumente.

  1. stat — obiectul de stat pentru cererea noastră;
  2. getters — obiectul store.getters, ceea ce înseamnă că putem numi alți getters din magazinul nostru.

Fiecare getter pe care îl declarați va necesita primul argument de stat. Și, în funcție de modul în care vă proiectați codul, getters se pot referi unul la altul folosind al doilea argument „getters”.

Să facem o generare de nume de familie care pur și simplu elimină valoarea prenumelui nostru din proprietatea noastră de stat a numelui complet. Acest exemplu ar necesita atât obiectele state, cât și obiectele getters.

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

Sfat: transmiteți argumente personalizate către Vuex Getters

O altă caracteristică interesantă a getter-ului este că le putem transmite argumente personalizate făcându-l pe getter să returneze o metodă.

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

3. Mutații

Mutațiile sunt singura modalitate de a schimba corect valoarea obiectului de stare. Un detaliu important de remarcat este că mutațiile trebuie să fie sincrone .

La fel ca geterii, mutațiile acceptă întotdeauna proprietatea de stat Vuex ca prim argument. Acceptă, de asemenea, un argument personalizat - numit sarcină utilă - ca al doilea argument.

De exemplu, să facem o mutație pentru a schimba numele unui utilizator într-o anumită valoare.

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

Apoi, putem apela această metodă din componenta noastră folosind metoda store.commit , cu sarcina noastră utilă ca al doilea argument.

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

De cele mai multe ori, veți dori ca sarcina dvs. utilă să fie un obiect. Acest lucru nu înseamnă doar că puteți transmite mai multe argumente unei mutații, dar, de asemenea, face codul mai ușor de citit datorită numelor de proprietăți din obiectul dvs.

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

Există două moduri diferite de a apela mutații cu o sarcină utilă.

  1. Puteți avea tipul de mutație ca prim argument și sarcina utilă ca al doilea.
  2. Puteți declara pass un singur obiect, cu o proprietate pentru tip și alta pentru sarcina utilă.
 this.$store.commit("changeName", { newName: "New Name 1", }); // or this.$store.commit({ type: "changeName", newName: "New Name 2" });

Nu există o diferență reală între modul în care funcționează cele două, așa că depinde în totalitate de preferințele personale. Amintiți-vă că cel mai bine este întotdeauna să fiți consecvenți pe parcursul întregului dvs. proiect, așa că, indiferent pe care îl alegeți, rămâneți cu el!

4. Acțiuni

În Vuex, acțiunile sunt destul de asemănătoare cu mutațiile, deoarece le folosim pentru a schimba starea. Cu toate acestea, acțiunile nu schimbă valorile în sine. În schimb, acțiunile comit mutații.

De asemenea, în timp ce mutațiile Vuex trebuie să fie sincrone, acțiunile nu. Folosind acțiuni, putem apela o mutație după un apel API, de exemplu.

În timp ce majoritatea gestionanților Vuex pe care i-am văzut acceptă starea ca parametru principal, acțiunile acceptă un obiect context. Acest obiect context ne permite să accesăm proprietățile din magazinul nostru Vuex (de exemplu, stare, commit, getters).

Iată un exemplu de acțiune Vuex care așteaptă două secunde și apoi comite mutația changeName .

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

În interiorul componentelor noastre, folosim metoda store.dispatch pentru a rula funcția noastră. Transmitem argumente la fel cum am făcut cu mutațiile. Declaram tipul si trecem orice argument personalizat in al doilea argument.

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

Încheierea

Acum, ar trebui să cunoașteți trei moduri diferite de a partaja date între componentele din VueJS: elemente de recuzită, evenimente personalizate și un magazin Vuex.

Sper că acest tutorial v-a ajutat să vă ofere mai multe informații despre unele metode și cele mai bune practici Vue diferite. Spune-mi cum le-ai implementat în proiectele tale!

Lectură suplimentară

Dacă sunteți interesat să aprofundați și mai mult latura/capacitățile tehnice ale fiecărei tehnici, iată câteva locuri grozave pentru a începe.

  • Site-ul oficial al ghidului Vuex
  • Documente VueJS pentru recuzită și evenimente personalizate
  • „WTF este Vuex? Un ghid pentru începători pentru magazinul de date pentru aplicații Vue”, Anthony Gore, dezvoltatori Vue.js