Šta su svojstva Vue instance?
Pri definisanju nove Vue instance konstruktorska funkcija kao parametar prihvata objekat kroz koji se definišu sve opcije Vue instance. U okviru tog objekta Vue.js obezbedjuje već predefinisana svojstva svaka sa svojim karakteristikama, koja omogućavaju rad Vue aplikacije. Sledeća lista predstavlja osnovna svojstva svake Vue instance i njima se pristupa van instance sa predznakom $.
Pored njih su pomenuta i tri veoma važana svojstva: computed, methods i watch koja se ponašaju kao proksi (više o ovome pročitajte u članku “Pristup svojstivima Vue instance”).
“$el”
U okviru 3.0 verzije $el može da se koristi za pristup osnovnom DOM element-u, uglavnom kod komponenti koje koriste fragmente. Ipak je preporučeno da se od verzije 3.0 izbegava oslanjanje na $el već da se umesto njega koriste šablonske reference $refs kao direktan pristup DOM elementima.
U okviru 2.0 verzije sa svojstvom “el” definišemo HTML element nad koji će da “upravlja” Vue aplikacija:
HTML
1 |
<div id="nekiSelektor"></div> |
JavaScript
1 2 3 |
new Vue ({ el: "#nekiSelektor" }) |
“$data”
Kod “Options API-ija” u okviru “options objekta” se nalazi svojstvo “data” (“model” u MVVM) koje predstavlja sekciju vezanu za pristup i čuvanje podataka. Vue.js sva svojstva iz “data” objekta, rekurzivno konvertuje u getter/setters kako bi ih učinio “reaktivnim”. Objekat “data” mora biti jednostavan kako bi predstavljao samo podatke, pa sve API objekte browser-a (window, document…), kao i prototype svojstva objekta Vue.js ignoriše.
Svojstva koja počinju sa _ (underscore) ili sa $ (dolar znak) neće se ponašati kao proxi ka Vue instanci, jer su takvi nazivi u konfliktu s internim Vue.js svojstvima i metodama.
Svojstva data ima specifične privilegije i ponaša se kao “proxy” prema Vue instanci. To znači da prosledjuju svoja child svojstva direktno Vue instanci, a rezultat ovoga ponašanja je da su njegova child svojstva tzv. “top svojstva” (prva do instance), kojima se može pristupiti direktno sa “this” ključnom reči. Više o ovome pročitajte u članku “Pristup svojstvima Vue.js instance”
Primer
U verziji 3.0 “data” nije objekat već funkcija koja vraća promenjive, pogledajte primer:
1 2 3 4 5 6 7 8 9 |
let app = Vue.createApp({ data () { return { msg: "Neki tekst" } } }); let vm = app.mount("#app") |
Ili sa direktnim instanciranjem ovako:
1 2 3 4 5 6 7 8 9 10 11 |
// direct instance creation const data = { a: 1 } // The object is added to a component instance const vm = createApp({ data() { return data } }).mount('#app') console.log(vm.a) // => 1 |
Primer (3.0 ver):
See the Pen
Untitled by Web programiranje (@chos)
on CodePen.
Kod verzije 2.0 “data” je standardno svojstvo objekta, koje je i samo objekat, pogledajte prime:
1 2 3 4 5 6 |
var vm = new Vue({ data: { a: 1, b: 3 } }) |
ili
1 2 3 4 5 6 7 8 |
var podaci = { a: 1, b: 3 } var vm = new Vue({ data: podaci }) |
Nakon kreiranja Vue instance više se ne mogu dodavati reaktivna data svojstva. Zbog toga se preporučuje da se takva svojstva unapred definišu, pre nego što se kreira instanca (da bi Vue.js mogao da ih obradi i definiše kao rekativna). Treba napomenuti da iako ne mogu da se naknadno dodaju tzv. “root-level” reaktivna svojstva, moguće je naknadno dodati nova svojstva u okviru već definisanih “root-level” rektivnih svojstava sa sledećpm sintaksom:
1 |
this.$set(this.someObject, 'b', 2) |
“Composition API” je dostupan samo uz verziju 3.0 i tada se u okviru “options objekta” ne koristi više “data” svojstvo, već se podaci čuvaju kao obične JS promenjive u okviru setup() funkcije. Da bi ta promenjiva bila dostupna i van Vue instance tj. u okviru HTML-a neophodno je u okviru setup() funkcije vratiti je sa return.
1 2 3 4 5 6 7 |
let app = Vue.createApp({ setup(props, context) { let msg = "Neka poruka" return { msg } } }) let vm = app.mount('#vue_app') |
Reaktivnost promenjive
Ova promenjiva sada može da se koristi u okviru HTML-a tj. da se prikaže kroz interpolaciju, medjutim ona i dalje nije reaktivna kao data svojstvo. Da bi promenjiva u sklopu setup() funkcije imala potpuno iste osobine kao neko “data” svojstvo (tj. da bi bila reaktivna), postoje dva načina:
a) Reaktivnost sa ref()
Prvi način je namenjen za rada sa primitivnim tipovima podataka i dovoljno je vrednost promenjive “obaviti” se Vue.ref() metodom:
1 |
let msg = Vue.ref("Neka poruka") |
Pristup vrednosti ovako definisane promenjive u okviru same Vue instance je sa promenjeva.value, dok se u okviru HTML-a koristi bez “.value”.
See the Pen
Untitled by Web programiranje (@chos)
on CodePen.
b) Reaktivnost sa reactive()
Ukoliko imamo objekat potrebno je “obaviti” ga sa Vue.reactive() funkcijom. U ovome slučaju nije potrebno koristi .value sintaksu za dobijanje vrednosti promenjive, pogledajte primer:
See the Pen
Composition API – reactive() by Web programiranje (@chos)
on CodePen.
“$refs”
U sklopu HTML koda koji “nadgleda” Vue aplikacija, zbog jednostavnijeg targetiranja HTML elemenata, možemo “obeležiti” željeni HTML element. Obeležavanje HTML elementa se vrši dodavanjem atributa ref u okviru nekog HTML tag-a.
1 |
ref="nekiNazivZaRaspoznavanje" |
na primer:
1 |
<h4 ref="naslov">Naslov Aplikacije</h4> |
Ovakvo obeleženom elementu iz Vue instance se pristupa sa:
1 |
this.$refs.nekiNazivZaRaspoznavanje |
Prethodni primer bi vratio ceo HTML element, te ukoliko želimo sadržaj tog elementa moramo dodatno da mu pristupimo npr.
1 |
this.$refs.naslov.innerText |
Treba napomenuti da $refs ima vrednost samo nakon što je komponenta renderovana i ta promenjiva nije reaktivna stoga treba izbegavati korištenje $refs u okviru template-a ili “computed properties”.
Primer
See the Pen
Vue $ref by Web programiranje (@chos)
on CodePen.
“methods”
Funkcije vezane za Vue instancu tzv. “metode” su u sklopu “Options API-ija” su predstavljene kao funkcije u okviru “methods” svojstva, dok su kod Composition API-ija funkcije u okviru “setup” svojstva. Metode se najčešće koriste kada želite da se nešto izvrši nakon nekog događaja. Treba naglasiti da se “Metode” u okviru interpolacije izvršavaju pri učitavanju instance (komponente) kao i pri svakom re-renderovanju strance. Ovakvo ponašanje metoda je omogućeno time što Vue.js ne vodi računa šta se nalazi u okviru metode pa će metoda, biti ponovo proračunata čak iako promena ne utiče na metodu.
When this data changes, the view will re-render. Method invocation will always run the function whenever a re-render happens.
Dokumentacija Vue.js
Primer
U ovome primeru imamo dve metode (“stampajA()” i “stampajB()”) čije su funkcionalnost jednostavne i opisane samim nazivom metode. Medjutim funkcionalnost koja je važna u ovome primeru je da se obe metode izvrše (vidi se po ispisu u konzoli) svaki put kada se re-renderuje stranica. Kao prva stvar na koju treba obratiti pažnju je činjenica da se odmah nakon učitavanja Vue instance u konzoli ispisuju poruke iz obe metode, što potvrdjuje činjenicu da se metode izvršavaju pri svakom učitavanju Vue instance (komponente).
Zatim treba pratiti konzolu nakon svakog klika na akciono dugme, jer se nakon svakog klika ispisuju po dve nove poruke, bez obzira koje dugme je kliknuto.
See the Pen Specifičnost metoda u Vue.js by Web programiranje (@chos) on CodePen.
See the Pen
Composition api metode by Web programiranje (@chos)
on CodePen.
Zaključak:
Sa prethodnim primerom smo pokazali da se obe metode izvršavaju svaki put kada se re-renderuje DOM nakon promene nekog od data svojstava, pa čak i metoda na koju promena data svojstva ne utiče, stoga zbog svega pomenutog treba naglasiti da u slučaju čestog ažuriranja user interfejsa, može doći do problema sa preformansama aplikacije, jer se troše resursi pri ponovnom pokretanja svih metoda. Na primer, ako imamo aplikaciju koja prikazuje tajmer koji se ažurira posle svake sekund, sve funkcije u okviu “methods” objekta će biti pozivane za izvršenje posle svake sekunde, i ponovno izračunati bez obzira na to koja im je namena. U ovakvom slučaju je preporuka koristi computed properties.
“computed”
“Computed” svojstva su u produžena ruka data svojstva, ona takodje vraćaju vrednost kao i data svojstvo:
See the Pen
Computed je extenzija data svojstva by Web programiranje (@chos)
on CodePen.
See the Pen
Composition APi – computed by Web programiranje (@chos)
on CodePen.
Iz prethodnog primera se vidi da su “computed svojstva” veoma korisna za manipulisanje sa već postojećim podacima. Pošto kao i data uvek vraćaju vrednost onda ime takve funkcije postaje svojstvo te se u aplikaciji koristi isto kao što koristimo “data” svojstvo (ne moramo ga pozivamo kao metodu). U suštini, “computed” svojstva su varijable, čije vrednosti zavise od drugih faktora i neće se ponovno izračunavati ako se zavisnosti ne promene. Što implicira da će funkcija iskoristiti svoju već prethodno izračunatu (tzv.kaširanu) vrednost, dok god nema promene zavisnosti.
Computed svojstva nisu namenjene za memorisanje podataka, štaviše, ako “computed” svojstvo vraća objekat, to će uvek biti novi objekat, a ne modifikovana verzija prethodnog. “Computed” svojstva moraju da budu funkcije čije akcije moraju da budu sinhrone i ne bi trebalo da imaju sporedne efekte.
Kada koristiti Computed properties?
Funkcije unutar “computed” svojstva se koriste kad god imamo neke podatke sa kojima trebamo da manipulišemo, da se transformišu, filtriraju, a pre nego što ih iskoristimo u template. Koristite “computed” svojstva kada želite da mutirate svojstvo koje zavisi od promene drugog svojstva koja se menja. “Computed” svojstva treba koristiti kao zamenu za inline izraze u okviru template kada imamo složeniju logiku.
Neki od primera zadataka koji su dobri kandidati za korišćenje “computed” svojstava su:
- Ažuriranje velike količine informacija dok korisnik piše, kao što je filtriranje liste
- Prikupljanje informacija iz “Vuex store”
- Validacija forme
- Vizualizacije podataka koje se menjaju u zavisnosti od toga šta korisnik treba da vidi
Primer
U ovom primeru je prikazano korišćenje “computed” svojstva za veliki set operacija:
1 2 3 4 5 6 |
computed: { velikiProracun () { // ... neki veliki proračun koji nakon nekog vremena vraća rezultat return 2 } } |
Sada rezultat ovih “teških” proračuna možemo koristiti iznova i iznova u okviru drugih operacija bez bojazni da će se ponovo proračunavati ako nema potrebe (tj. ako se nisu promenile :
1 2 3 4 5 |
methods: { jednostavniProracun (input) { return input * this.velikiProracun } } |
Da li koristiti “computed” ili “methods” svojstvo?
Ovu dilemu ću pokušati da objasnim kroz primer u kome iako koristimo različita svojstva dobijamo istu krajnju funkcoionalnost.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div id="example"> <p>Originalna poruka: "{{ message }}"</p> <p>Obrnuta poruka: "{{ reversedMessage() }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, methods: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div id="example"> <p>Originalna poruka: "{{ message }}"</p> <p>Obrnuta poruka: "{{ reversedMessage }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { reversedMessage: function () { return this.message.split('').reverse().join('') } } }) </script> |
Krajnji rezultat je jednak, ali to ne znači da razlika ne postoji. Funkcija unutar “methods” će se izvršiti svaki put kada se renderuje stranica tj. pri svakoj mogućoj promeni DOM-a (ne samo promena svojstva “messages”), dok pri korišćenju computed svojstva Vue pamti vrednost svojstva od koje computed svojstvo zavisi (messages) i proračunava computed svojstvo samo ako se “dependency” promeni, u svakom drugom slučaju vraća keširanu vrednost.
Zaključujemo:
ako logika naše aplikacije ima “teške” proračune, a ne zahteva ponovno proračunavanje svojstva pri svakom renederovanju stranice, treba koristi “computed” svojstvo (jer dobijamo na perfomansama zbog keširanja). Medjutim ako logika zahteva ponovni proračun pri svakom renderovanju stranice tj. pri bilo kakvoj promeni (ne samo promeni zavisnosti), onda koristite koristite “methods”.
NAPOMENA:
Ako se computed svojstvo koristi u okviru duplih vitičastih zagrada tj. ako se izvršava interpolacija JavaScript izraza, onda se samo navodi naziv “computed” svojstva (bez zagrada koje označavaju pozivanje i izvršavanje funkcije)
npr.
{{ nekoComputedSvojstvo }}
Ovo je još jedna sličnost sa “data” svojstvom jer “computed” svojstvo uvek vraća neku vrednost, stoga praktično mi očekujemo da se namestu interpolacije štampa ta pripremljena (keširana) vrednost.
Computed svojstvo po default-u ima samo get-er:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
computed: { fullName() { return this.firstName + ' ' + this.lastName } //ili drugacije napisano: fullName: { get() { return this.firstName + ' ' + this.lastName } } } |
Medjutim oni mogu da obezbede i set-er ako je potrebno:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
computed: { fullName: { get() { return this.firstName + ' ' + this.lastName }, set(newValue) { const names = newValue.split(' ') this.firstName = names[0] this.lastName = names[names.length - 1] } } } |
Primer
See the Pen
Computed Vue by Web programiranje (@chos)
on CodePen.
“watch”
Svojstvo “watch” pruža dodatni nivo kontrole, i omogućavaju nam da pratimo promene u modelu (data). Funkcije unutar “watch” objekta se aktiviraju samo kada se promeni određeno svojstvo u okviru data objekta. Treba naglasiti da “watched” svojstvo može da prati promene samo na jednom svojstvu
1 2 3 4 5 6 7 8 9 10 11 12 13 |
new Vue({ el: '#demo', data: { firstName: 'Foo', lastName: 'Bar', fullName: 'Foo Bar' }, watch: { firstName: function (val) { this.fullName = val + ' ' + this.lastName } } }) |
NAPOMENA:
Naziv watchera mora biti isti kao naziv data svojstva čiju promenu prati. Kroz parametar watch funkcije se prosledjuje promenjena vrednost data svojstva koju “nadgledamo”
Deep watch
Da bi smo pratili nestovana (ugnježdena) svojstva nekog objekta, potrebno je da definišemo vrednost parametra “deep” na “true”:
1 2 3 4 5 6 7 8 |
watch: { nekoSvojstvo: { handler: function () { ... }, deep: true } } |
Composition API ima prednost jer može da prati više promenjivih od jednom, dovoljeno je ih je proslediti watch metodi kao prvi parametar, drugi parametar je callback metoda.
See the Pen
Composition API – watched by Web programiranje (@chos)
on CodePen.
Calback metoda ima dva ugradjena parametra pa ako odgovara mogu i oni da se koriste umesto da se targetira promenjiva koja se prati, pogledajte primer:
1 2 3 |
Vue.watch(value, (newValue, oldValue) => { console.log("Nova vresnost je " + newValue + " a stara je: " + oldValue); }); |
A u slučaju da se prate dva podatka kao u prošlom primeru:
1 2 3 |
Vue.watch([ime, prezime], ([newIme, newPrezime],[oldIme, oldPrezime]) => { punoIme.value = newIme +" " + newPrezime; }); |
Kada koristiti watch svojstvo?
“Watch” svojstva su specifičnija od computed svojstava i samim tim im je uže polje delovanja pa se i redje koriste. Koristite ih kada je potrebno da izvršite neku logiku nakon promene odredjenog child svojstva u okviru “data” objeka, pri čemu je željana akcija:
- asihrona operacija
- proračun tzv. medjurezultata
- dodatno smanjivanje broja aktiviranja odredjenih operacija (npr. debounce nad input dogadjajem)
Pored pomenutih slučajeva možemo primeniti watch i za mnoge druge funkcionalnosti ali to treba dobro proceniti, jer iako je izvršavanje neke funkcionalnost sa “watch” svojstvom izvodljivo, to ne znači da je i preporučljivo, jer može biti komplikovanije nego da koristimo “computed” svojstvo. Zaključak je da “watch” svojstvo treba koristiti tek kada “computed” svojstva ne mogu rešiti vaš problem.
Primer
U ovome primeru je prikazana situacija kada problem ne možemo da rešimo sa “computed” svojstvom. Jedan od razloga za korišćenje “watch” svojstva u ovome primeru je izvršavanje asihrone operacije unutar nje, a drugi je definisanje medjurezulta (answer), dok se ne dobije finalni odgovor. Ni jedan od ovih zadataka ne bi mogao da se uradi sa “computed” svojstvom.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
new Vue({ el: '#watch-example', data: { question: '', answer: 'I cannot give you an answer until you ask a question!' }, watch: { question: function (newQuestion, oldQuestion) { this.answer = 'Waiting for you to stop typing...' this.nekiAsinhroniZahtev() } }, . . . }) |
Primer
U ovome primeru koristimo svojstvo “searchQuery” sa kojim pratimo promenu istoimenog data svojstva, nakon čega upućujemo asinhroni zahtev serveru:
See the Pen Watch svojstvo za asinhroni zahtev serveru by Web programiranje (@chos) on CodePen.
Konfiguracija instance
U verziji 3.0 svaka Vue aplikacija ima konfiguracioni objekat koji sadrži podešavanja konfiguracije za tu instancu aplikacije:
1 2 3 |
const app = createApp({}) app.config = {...} |
Ovo je globalni objekat i može mu se pristupiti iz bilo koje instance ili komponente unutar aplikacije. Ovo su neka od svojstava tog konfiguracionog globalnog objekta:
- errorHandler
- warnHandler
- globalProperties možemo pristupiti iz bilo koje instance komponente unutar aplikacije, pogledajte primer:
123456app.config.globalProperties.foo = 'bar'app.component('child-component', {mounted() {console.log(this.foo) // 'bar'}})
U verziji 2.0 globalna promenjiva je mogla da se sačuva sa Vue.prototype
1Vue.prototype.$myGlobalVariable = globalVariable - compilerOptions
- …