Frontend-applikasjoner, spesielt de mer komplekse, må behandle mye data. Programmerere introduserer ulike designmønstre for å gjøre prosjektene lesbare og vedlikeholdbare. I de fleste vanlige scenarier med MVC ønsker vi å skille dataene fra de visuelle delene av appen.
Det er grunnen til at butikk har blitt så nyttig. Det er opp til deg om du vil bruke React + Redux eller Vue + Vuex - hovedmålet er det samme, nemlig holder dataene dine strukturerte, tilgjengelige og trygge på samme tid.
I denne artikkelen skal jeg vise deg noen eksempler på hvordan du kan holde Vuex-butikken ren og effektiv.
Før vi begynner, la oss anta at:
- du har litt erfaring med moderne JavaScript,
- vet du i utgangspunktet hva Vue er og hvordan du bruker rekvisitter, beregnet, osv,
- du er kjent med Vuex (handlinger, mutasjoner, etc.) og ønsker å gjøre appene dine bedre.
Vuexsom de fleste av de viktigste Vue-prosjekterer ganske godt dokumentert, og du kan finne mange nyttige hacks i de offisielle dokumentene. Vi har hentet ut noe viktig informasjon fra den for deg.
En grunnleggende Vuex-butikkimplementering ser slik ut:
// main.js
import Vue from 'vue'
import Vuex from 'vuex'
import App from "./App";
Vue.use(Vuex)
const store = ny Vuex.Store((
tilstand: (
data: null;
),
actions: (
someAction: (( commit ), data) (
commit("SOME_MUTATION", data);
)
),
mutasjoner: (
SOME_MUTATION (tilstand, data) (
state.data = data;
)
))
));
new Vue((
el: "#app",
render: h => h(App),
store
));
Når appen blir større, må du vanligvis bruke ruting, noen globale direktiver, plugins osv. Det gjør main.js
filen mye lengre og vanskeligere å lese. Det er en god idé å oppbevare lagringen i en ekstern fil, som her:
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const state = (
data: null;
);
const actions = (
someAction: (( commit ), data) (
commit("SOME_MUTATION", data);
)
);
const mutations = (
SOME_MUTATION (tilstand, data) (
state.data = data;
)
);
export default new Vuex.Store((
state,
handlinger,
mutasjoner
));
1. Moduler
Hva bør du gjøre når store.js
filen blir enorm og vanskelig å jobbe med? Det finnes faktisk en veldig kul funksjon i Vuex - moduler. De er dedikert til å dele dataene dine i separate filer.
Tenk deg at du jobber med en bedriftsapp, der du for eksempel har noen få datadomener:
- bruker (administrerer alle autorisasjoner og tillatelser),
- ruteparametere (administrer globale parametere før forespørsler til API),
- salg (for SalesMegaChart-komponenten som er synlig i en månedlig/kvartalsvis/årlig kontekst),
- bestillinger (synlig etter at du har klikket på SalesMegaChart-linjen).
...og kanskje noen flere. Nå har du gode grunner til å innføre modularitet i butikken din.
Først og fremst må du flytte store.js
fil til en nyopprettet butikk/
katalogen og gi den nytt navn index.js
. Hvis du vil beholde alt samlet i moduler, kan du eventuelt fjerne stat, handlinger og mutasjoner fra hovedfilen.
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store((
moduler: (
// moduler vil gå her
)
));
Deretter, ved siden av filen `store/index.js`, oppretter du den første modulen - `store/user.js`.
import ApiService fra '../services/api.service';
const state = (
loggedIn: false,
loginError: null,
user: null
);
const actions = (
login: async (( commit ), data) (
try (
const response = await ApiService.post('/login', data);
const ( user ) = response.data;
COMMIT("SAVE_USER", bruker);
COMMIT("LOGIN_SUCCESS");
) catch (feil) (
commit("LOGIN_ERROR", feil);
)
)
);
mutasjoner = (
SAVE_USER (state, bruker) (
state.user = user;
),
LOGIN_SUCCESS (state) (
state.loggedIn = true; )
),
LOGIN_ERROR (state, feil) (
state.loginError = error;
state.loggedIn = false;
)
);
export const user (
state,
handlinger,
mutasjoner
)
Og nå laster du inn den ferdige modulen i hovedfilen `store/index.js`:
import Vue fra 'vue'
import Vuex fra 'vuex'
import ( user ) from './user';
Vue.use(Vuex);
export default new Vuex.Store((
moduler: (
bruker
)
));
Gratulerer så mye! Nå har du en virkelig flott butikkimplementasjon. Du kan også få tilgang til dataene fra komponenten (f.eks, UserProfile.vue
) som dette:
<template>
<div class="user-profile">
<h2>(( bruker.navn ))!</h2>
<!-- component template goes here -->
</div>
</template>
<script> import ( mapActions ) from 'Vuex';
export default (
name: 'UserProfile',
computed: mapState((
user: state => state.user
// user: 'user' <-- alternative syntax
))
)
</script>
2. Navnerom
Nå som du vet hvordan du bruker modulene, bør du også gjøre deg kjent med Vuex' navneplassering. I det forrige trinnet opprettet vi store/user.js
filen med bruker modul.
Datastrukturen som er definert i user.js
filen er tilgjengelig fra komponenter, men du kan se at alle bruker data går direkte til den globale stat
kontekst, som her:
beregnet: mapState((
user: state => state.user
// bruker: 'user' <-- alternativ måte
))
Når du definerer flere moduler, vil du sannsynligvis bli forvirret over hvilket objekt som kommer fra hvilken modul. Da bør du bruke navngitte moduler og definere dem på denne måten:
export const user (
namespaced: true, // <-- namespacing!
state,
handlinger,
mutasjoner
)
Fra nå av vil alle dine bruker data (stat
variabel fra store/user.js
filen) vil bli håndtert under state.user
referanse:
beregnet: mapState((
user: state => state.user.user
// bruker: 'user/user' <-- alternativ måte
))
Noen få trinn senere kan du oppnå noe slikt for komponenten:
import ( mapActions ) fra 'Vuex';
eksporter standard (
navn: 'Dashboard',
computed: mapState((
salg: 'salg/data',
bestillinger: 'bestillinger/data',
sortBy: 'bestillinger/sortBy',
loggedIn: 'bruker/loggedIn'
)),
methods: mapActions((
logout: 'user/logout', 'user/logout',
loadSales: 'salg/load',
loadOrders: 'bestillinger/load'
)),
created() (
if (this.loggedIn) (
loadSales();
loadOrders();
)
)
)
Bravo! Så friskt, så rent ... Men ikke vær redd, refaktorisering tar aldri slutt. Klar for de neste trinnene?
3. Kommunikasjon mellom moduler
I det første trinnet viste jeg deg noen handlinger i bruker modul:
const actions = (
login: async (( commit ), data) (
try (
const response = await ApiService.post('/login', data);
const ( user ) = response.data;
COMMIT("SAVE_USER", bruker);
COMMIT("LOGIN_SUCCESS");
) catch (feil) (
commit("LOGIN_ERROR", feil);
)
)
);
I tilfelle feil, legger vi til påloggingsfeil i butikken vår - hva blir det neste?
Her har vi noen alternativer, og valget avhenger av hvilket alternativ som passer best til dine behov. Den enkleste måten er å bruke v-if
direktivet, som gjør det mulig å vise en feilmelding hvis det oppstår en feil i butikken din.
<template>
<div class="dashboard">
<!-- dashboard component template -->
<div
v-if="error"
class="error-message"
> (( feil.melding )) </div>
</div>
</template>
<script> import ( mapActions ) from 'Vuex';
export default (
name: 'Dashboard',
computed: mapState((
error: "user/loginError"
))
)
</script>
Igjen, tenk deg at du har mange moduler, og at hver try/catch
syntaksen genererer en ny feil i butikken din. Det er klart at du kommer til å misbruke DRY-regelen på denne måten.
Hvordan kan du gjøre feilhåndteringsprosessene dine mer generiske?
La oss definere felles modulen og legge inn noe logikk der som skal brukes globalt.
// store/common.js
const state = (
errors: []
);
const actions = (
feil: (
root: true,
handler((( commit ), error) (
commit("ERROR", feil);
)
)
),
mutasjoner = (
ERROR (tilstand, feil) (
/* på denne måten vil vi ha den nyeste feilen øverst på listen */
state.errors = [error, ...state.errors];
))
);
export const common (
namespaced: true,
state,
mutasjoner
)
Nå kan vi tilpasse bruker modulen (og andre moduler også):
try (
// en eller annen handling
)catch (feil) (
commit("common/ERROR", error, ( root: true ));
)
eller på en mer elegant måte, ved å bruke vår globale handling:
try (
// en eller annen handling
) catch (feil) (
dispatch("error", feil);
)
Denne syntaksen av forplikte
og utsendelse
samtaler virker selvforklarende, men du kan lese mer om disse triksene her.
Når du har alle feilene på ett sted, kan du enkelt laste dem inn i Dashbord
komponent:
beregnet: mapState((
errors: 'vanlig/feil'
)),
watch: (
/* denne vil bli påkalt etter hver "common/ERROR"-mutasjon, der vi bare legger til nye feil i lageret, én etter én */
errors() (
this.showErrorMessage(this.errors[0]);
)
)
Det forrige eksempelet med felles er allerede en effektiv løsning, men du kan gå enda lenger.
Som du kan se, ser vi endringer på vanlige/feil
matrisen i butikken. I tilfeller som dette, når du trenger å bestemme en handling på en bestemt mutasjon, kan du bruke Vuex-plugins eller til og med Higher Order Components (HOC).
Jeg vil diskutere plugins og HOC-er i neste artikkel. I mellomtiden, takk for at du leste dette innlegget, og forhåpentligvis likte du eksemplene vi har forberedt.
Følg med og fortsett å kode!
Les mer om dette:
– Hvordan forbedre Vue.js-apper? Noen praktiske tips
– GraphQL: Erfaringer fra produksjon
– Shopify, Spree eller Solidus? Sjekk hvorfor Ruby on Rails kan hjelpe deg med å utvikle din e-handel