Sdílení dat ve Vue
Komponenty. Moderní web jsou komponenty. Části kódu, které lze recyklovat, nezávisle upravovat a jednoduše nahrazovat staré za nové. Každá z nich je v ideálním světě kompletně izolovaná od ostatních a na webu plní pouze jednu funkci. Znáte to klišé “jednu chybu opravím a tři nové vytvořím”, že? Komponenty dokážou takové situaci předejít. Ideální svět ale neexistuje a ani mezi komponentami nelze udržovat kompletní social distancing. Potřebují se potkávat a povídat si.
V Apploudu píšeme weby (např. https://mtxgroup.cz/, https://zrychlujemecesko.cz/) ve Vue a našim komponentám nasazujeme roušky v podobě TypeScriptu a striktních pravidel, aby si mohly povídat bezpečně. Naším cílem je psát přehledný a udržovatelný kód. K tomu nám pomáhají knihovny vue-property-decorator (https://github.com/kaorun343/vue-property-decorator) a vuex-class (https://github.com/ktsn/vuex-class/), s nimiž je bezpečná výměna dat hotový no-brainer.
Informace sdílené v (libovolném) webovém frameworku můžeme rozdělit podle jejich scopu, tzn. kdo všechno k nim má přístup. My to vidíme takto:
- Lokální scope - informace s lokálním scopem je izolovaná v komponentě, každá instance komponenty má svou vlastní nezávislou kopii.
- Globální scope - informace je přístupná prakticky odkudkoliv, neboť je definovaná uvnitř Vuex Storu.
Sdílení lokálních informací
Informace s lokálním scopem jsou ve Vue proměnné definované v data funkci, nebo jako v našem případě s vue-class-component instanční proměnné. Při jejich sdílení napříč hierarchií komponent se řídíme zlatým pravidlem “props down, events up”. Přesně tento účel plní dekorátory @Prop a @Emit.
<template>
<Child :value="foo" @increase="foo = $event" />
</template>
@Component({})
class Parent extends Vue {
private foo: number = 0;
}
<template>
<button @click="increase" />
</template>
@Component({})
class Child extends Vue {
@Prop() value: number;
@Emit()
increase() {
return this.value + 1;
}
}
Každý zkušený programátor má rád abstrakci a obecná řešení, proto s radostí používáme i dekorátor @VModel, se kterým je předávání informací ještě jednodušší.
<template>
<Child v-model="foo" />
</template>
@Component({})
class Parent extends Vue {
private foo: number = 0;
}
<template>
<button @click="vModel++" />
</template>
@Component({})
class Child extends Vue {
@VModel() vModel: number;
}
Sdílení globálních informací
Některé informace jsou tak důležité, že mají vliv na celý web - např. údaje o přihlášeném uživateli. Přístup by k nim měla mít každá komponenta, která podle nich mění svůj obsah. Zároveň by bylo naprosto kontraproduktivní, aby měla každá komponenta vlastní kopii uživatelských dat, nebo si je sama stahovala ze serveru. Skvělým řešením je v tomto případě Vuex store, který řídí stahování dat a distribuci informací do všech komponent. Ovšem ještě lepším řešením je sada dekorátorů z vuex-class. Získávání dat ze storu je díky nim kratší, organizovanější a zábavnější!
class NewsDetail extends Vue {
@State readonly recentArticles: Article[] | null;
@State readonly article: Article | null;
@Action fetchRecentArticles: () => Promise<void>;
@Action fetchArticle: (id: string) => Promise<void>;
@Mutation setArticle: (payload: Article | null) => void;
async created() {
await Promise.all([
this.fetchRecentArticles(),
this.fetchArticle(this.$route.params.id),
]);
}
beforeDestroy() {
this.setArticle(null);
}
}
Dekorátory jsou výborným nástrojem JavaScriptu (doufáme, že brzo oficiálním - https://tc39.es/proposal-decorators/), který i ve Vue aplikacích najde své uplatnění. Jejich zásluhou je náš kód doslova krásnější ;)