Comunicare între componente
Last updated
Last updated
Aplicațiile Web deobicei nu sunt compuse dintr-o singură componentă, ci din mai multe componente care toate impreună îndeplinesc funcționalitatea noastră. În general, se obișnuiește organizarea aplicației într-un arbore de componente imbricate:
Deobicei avem o coponenta parinte, care reprezintă însăși pagina, și ea include o serie de componente copii, care la rândul său pot avea alți copii.
Spre exemplu, am putea avea componente pentru header, sidebar și content area, fiecare conținând, de obicei, alte componente pentru blog posts, link-uri de navigare ș.a.
Aceste componente trebuie să comunice intre ele pentru a oferi o funcționalitate integrată. Avem 2 direcții de comunicare:
De la părinte spre copil - componenta parinte transmite informație catre o componentă copil
De la copil spre părinte - componenta copil informează părintele că au intervenit modificări
Să presupunem că vrem să implementăm o pagină, care ar avea o listă de comentarii, și fiecare comentariu are text, un autor, si un număr like-uri care le-a primit.
O structură clasică a acestei funcționalități ar fi o componentă care reprezintă un comentariu, și o componentă părinte - pagina. Pagina va include o listă de componente Comment
în ea.
Desigur comentariile vor fi păstrate în pagina părinte, ca o listă de obiecte, respectiv avem nevoie de un mecanism să transmitem către elementul copil informația necesară.
Pentru a defini o componentă care acceptă o proprietate, folosim attributul props
în declararația JavaScript. Astfel acel prop poate fi folosit în mod similar ca și data
Pentru fiecare proprietate a componentei e recomandabil să setăm tipul de date care-l așteptăm. În acest caz - String
Pentru a folosi această componentă, doar îi transmitem proprietatea cerută când o declarăm:
E important să importăm componenta folosită, și să o declarăm în components
Desigur, nu e cel mai practic să transmitem un text static. Vue permite să transmitem valori dinamice către sub-componente în mod similar cum transmitem și pentru atribute standarte html
În programare avem câțiva termeni care definesc convenții de unire a mai multor cuvinte într-o singură expresie, 2 din ele:
CameCase - înseamnă că fiecare cuvânt nou din expresia noastră va începe cu literă mare. Toate și funcțiile în JavaScript, spre exemplu, e recomandat să respecte această convenție
kebab-case - înseamnă că unim cuvintele în expresia noastră cu -
, și toate sunt cu litere mici. Un exemplu unde se utilizează această convenție sunt atributele în html
Având această diferență de convenții între html și JavaScript, Vue a adoptat o regulă simplă: Definim proprietățile în JavaScript sub convenția CamelCase, iar când le transmitem din html, le transmitem sub kebab-case, și el va avea grijă să știe care și cui aparține:
Observați likesCount
în definiția JavaScript a componentei, și likes-count
când o utilizăm din componenta părinte.
Combinând toate învățate până acum ajungem la următoarele definiții pentru componenta copil Comment.vue
:
Și pagina părinte App.Vue
:
Array-ul de comentarii deja sunt obiecte, cu mai multe atribute în ele, și am inclus și un id
, care îl folosim ca :key
în v-for
Pe parcursul anilor de dezvoltare a tehnologiilor web, au fost învățate o serie de lecții și practici care par să fie cele mai bune. Una din aceste practici, este ideea de direcția de parcurgere a datelor.
În termeni simpli, toată ideea se bazeaza pe faptul că componentele copii primesc direct datele de la componente părinți prin proprietăți, dar nu pot modifica direct datele componentelor parinti. Dacă vor să comunice o schimbare, trebuie să emită un eveniment.
O altă concluzie a acestei practici este că interpretăm toate datele care le primim prin props
ca date nemodificabile. Asta inseamnă că nu putem să le folosim direct în forme prin v-model
, dacă vrem să le includem intr-o formă, le copiem întrun data
local, și îl folosim pe acela.
Extindem un pic lista noastră de comentarii, și adăguăm posibilitatea ca oamenii să dea like la fiecare comentariu. De asemenea vrem sa metinem un contor cu numărul total de like-uri care le-am primit:
Pentru a implementa funcționalitatea de a da like la fiecare comentariu, trebuie să adăugăm un buton care crește acel numă la fiecare click. Din cauza că nu putem modifica direct props
care le primim, trebuie să copiem valoarea care vine într-o variabilă locală a componentei:
Observați că likesCount
nu se modifică, doar copiem valoarea în internalLikes
și mai departe lucrăm doar cu ea.
În acest moment, fiecare număr din fiecare comentariu poate fi crescut, doar că numărul total de comentarii din pagina părinte nu se modifică, trebuie cumva să-i transmitem informația când se întâmplă un like.
Pentru a transmite din componenta copil către componenta părinte informația că a avut loc un like, trebuie să emitem un eveniment. Pentru asta trebuie să adaugăm o singură linie de cod în metoda likeComment()
:
Pentru a prelucra acest eveniment în componenta părinte, folosim aceeași sintaxă ca pentru evenimentele standarte html:
Spre deosebire de proprietăți, evenimentele e recomandat să le scriem întotdeauna cu kebab-case.
Motivul principal este că html nu face deosebire între litere mici și mari la atributele elementelor, respectiv likeChange
nu ar avea sens.
O convenție pentru numele metodelor care prelucrează evenimente e să le incepem cu on..
Dacă vrem să adaugăm și butonul dislike și să nu creăm eveniment cu nume nou, putem să transmitem date în evenimentele noastre:
Ca date într-un eveniment putem transmite atât tipuri simple de date (numere, string), cât și obiecte complexe, cum in cazul de mai sus - un obiect cu proprietatea likeDelta
Deobicei e recomandat să transmitem obiecte cu proprietăți, pentru a fi mai expliciți care e informația transmisă.
Pentru a prelucra aceste evenimente în componenta părinte trebuie să modificăm un pic prelucrarea pentru a primi evenimentul cu date:
Observați că în template transmitem variabila $event
când apelăm metoda onLikeChange($event)
. această variabilă e automat disponibilă și conține datele care au fost transmite de componenta Comment
De asemenea la declarația metodei în javascript am definit un parametru de intrare event
- care îl folosim pentru a modifica valoarea lui totalLikes
Astfel am implementat complet comunicarea inversă de la copil către părinte prin evenimente cu date.
Componenta Comment.vue
:
Și pagina părinte App.vue
: