Pineapple belongs in Vue: Using Stores in Vue app in 2023
Pineapple belongs in Vue: Using Stores in Vue app in 2023
Pineapple belongs in Vue: Using Stores in Vue app in 2023

Ananas do Vue patří: Použití Storu ve Vue aplikaci v roce 2023

Frontend

Ananas do Vue patří: Použití Storu ve Vue aplikaci v roce 2023

Frontend

Ananas do Vue patří: Použití Storu ve Vue aplikaci v roce 2023

Frontend

Pinia, nebo Vuex? Jednodušší volba, než jsme čekali.

21. 2. 2023

Pinia is the new black

Od počátků Vue byl Vuex jediná knihovna založená na Flux architektuře, která byla udržována a používána ke správě dat ve Vue aplikaci. Hlavně kvůli stringovým klíčům a nemožnosti mutovat stav jsme se ale Flux architekturu na našich projektech ostýchali používat. Minimálně do chvíle, než jsme objevili knihovnu, s níž je radost pracovat. Když ji navíc podporuje i samotný strůjce Vue Evan You, tak už není vůbec o čem přemýšlet.

Řeč je samozřejmě o Pinia.

Knihovna, co má za maskota ananas, zkrátka nemůže být špatná (Pinia)

Narozdíl od Vuexu, který nabízí jeden store s více moduly, je Pinia plně modulární. Lze tak vytvořit více storů a importovat je do jednotlivých komponent podle potřeby uživatele. Tím odpadá i peklo s psaním stringové mutace na lístečky a jejich následné lepení na monitor. Ve Vuex také nelze změnit stav přímo a musíme používat mutace. Ty ale udělají radost málokomu, a proto je třeba ocenit, když v Pinie můžeme měnit stav přímo.

Všechna stavová byrokracie byla údajně kvůli devtoolů. Ty v Pinie fungují více než skvěle, out-of-the-box!

Zamávejte propletenému props/event systému

Hlavní použití storových knihoven stojí na uchovávání dat z API. Mít jednu source-of-truth je mnohem příjemnější, než řešit, která komponenta vlastní aktuálnější data. Story pak můžeme rozdělit podle dat, která spravují, čímž získáme store pro tabulky, formuláře apod.

Tady ale náš globální stav aplikace nemusí končit. Zároveň si můžeme věci zjednodušit i napojením stavů modálů do storu. Komunikace přes event bus, případně poslouchání eventů, může zcela vymizet, a pokud si formulář chce otevřít načítací okno, které ale vlastní celá stránka, zavolá přímo store tohoto okna. Odzvoní tak potížím s přímými rodiči komponent a posíláním eventů napříč celou aplikací.

Pro ilustraci…

V moderních webových aplikací pracujeme se spoustou modálů, pro které bývá obtížné udržovat jejich stav (otevřen/zavřen) v rámci celé aplikace. Nabízí se proto řešení vytvořit pro každou podobnou komponentu vlastní store, který se bude starat o jejich stav.

export const useModalStore = defineStore('modal', () => {

    const modalOpen = ref(false)

    const open = (): void => {
    /* Anything we need to set when opening modal goes here */
    modalOpen.value = true
  }

    const close = (): void => {
    /* Anything we need to clear after closing modal goes here  */
    modalOpen.value = false
  }

    return {
        modalOpen,
        close,
        open,
  }
})

Na kterémkoliv místě, kde budeme chtít s tímto modálem pracovat, stačí jen importovat jeho store, čímž získáme možnost ho otevřít či zavřít nezávisle na tom, jak daleko jsme od komponenty modálu daleko.

Tenhle přístup se může zdát zbytečný v malé aplikaci, kde komunikují dvě komponenty stejné úrovně. Oddělením funkční logiky od html ale můžeme docílit mnohem čistšího kódu v html části komponent.

V klasické situaci, kdy používáme tabulku s rozjížděcím formulářem, může být komunikace v html sekci mezi formulářem a tabulkou zbytečně natažená a nepřehledná. Díky vytvoření storu pro tabulku a storu pro form dojde ke značnému zpřehlednění celé části.

Komunikace přes eventy:

<table-component>
	<template #detail="{ focusedItem }">
		<form :focusedItem="focusedItem" @cancel="formCanceled" @save="formCanceled"/>
	</template>
</table-component>

Komunikace přes store:

<table-component
	v-model:focusedItem="tableStore.focusedItem"
	v-model:isDetailOpen="tableStore.detailOpen"
>
	<template #detail>
		<table-form/>
	</template>
</table-component>

V souvislosti s tím musíme napojit tabulku na store, ale v celé aplikaci teď můžeme jednoduše ovlivňovat a zjišťovat stav tabulky a formuláře. Oba se spolu nemusí na přímo vůbec bavit, a z aplikace tedy odpadá potřeba zanořování propů a eventů a propagování změn napříč komponenty. Zároveň dosáhneme i čistšího a čitelnějšího html.

Setup Store

Po přechodu z options API, kterou nabízí Vue2, na fresh script setup ve Vue3 se člověku už těžce pracuje s archaickým options přístupem. Pinia nás v tomhle ohledu vůbec nezklamala a celý store lze napsat jako setup funkci. Dojde k několika změnám:

  • Z refů se stane state.

  • Z computed se stanou getter.

  • Z funkcí se stanou akce.

Díky setup přístupu můžeme do storu dát více logiky, která byla předtím svázána s aplikací. Příkladem budiž validace jednotlivých vstupů nebo nejrůznější watchery závislé na datech aplikace:

export const useModalStore = defineStore('modal', () => {

    const modalOpen = ref(false)

    const open = (): void => {
     /* Anything we need to set when opening modal goes here */
    modalOpen.value = true
  }

    const close = (): void => {
    /* Anything we need to clear after closing modal goes here  */
    modalOpen.value = false
  }

    watch(
		() => modalOpen.value,
		(val) => console.log('Modal je otevreny: ${val} ')
    )
    
   return {
       modalOpen,
       close,
       open,
  }
})

Tím vším získává Pinia velký náskok před konkurencí a jsme rádi, že se postupně stává standartem pro nové Vue projekty. Ostatně i Vue CLI ji nabízí jako defaultní store místo Vuex. Práce s ní je znatelně jednodušší a přehlednější než s jinými knihovnami založené na FLUX architektuře a přidávání dalších feature do projektu je mnohem rychlejší při precizním oddělení designu a práce s daty.

Podobné články

Podobné články

Podobné články