Frontend-applikationer, särskilt de mer komplexa, måste bearbeta mycket data. Programmerare introducerar olika designmönster för att göra sina projekt läsbara och underhållbara. I de flesta vanliga scenarier för att hantera en MVC vill vi separera data från de visuella delarna av appen.
Det är skälet till varför butik har blivit så användbart. Det är upp till dig om du använder React + Redux eller Vue + Vuex - huvudmålet är detsamma, nämligen hålla dina data strukturerade, tillgängliga och säkra på samma gång.
I den här artikeln ska jag visa dig några exempel på hur du kan hålla din Vuex-butik ren och effektiv.
Innan vi börjar, låt oss anta att:
- du har någon erfarenhet av moderna JavaScript,
- du vet i princip vad Vue är och hur man använder rekvisita, beräknat, etc,
- du är bekant med Vuex (åtgärder, mutationer, etc.) och vill göra dina appar bättre.
Vuex, liksom majoriteten av kärn Vue projektär ganska väldokumenterad och du kan hitta många användbara hack i officiella dokument. Vi har extraherat en del viktig information från den åt dig.
En grundläggande implementering av en Vuex-butik ser ut så här:
// main.js
import Vue från 'vue'
import Vuex från 'vuex'
import App från "./App";
Vue.use(Vuex)
const store = ny Vuex.Store((
tillstånd: (
data: null;
),
åtgärder: (
someAction: (( commit ), data) (
commit("SOME_MUTATION", data);
)
),
mutationer: (
SOME_MUTATION (tillstånd, data) (
tillstånd.data = data;
)
))
));
ny Vue((
el: "#app",
render: h => h(App),
butik
));
När din app blir större måste du vanligtvis tillämpa routing, vissa globala direktiv, plugins osv. Det gör att main.js
filen mycket längre och mer svårläst. Det är en bra idé att förvara lagringen i en extern fil, som här:
// butik.js
importera Vue från 'vue'
importera Vuex från 'vuex'
Vue.use(Vuex);
const tillstånd = (
data: null;
);
const åtgärder = (
someAction: (( commit ), data) (
commit("SOME_MUTATION", data);
)
);
mutationer = (
SOME_MUTATION (tillstånd, data) (
tillstånd.data = data;
)
);
export default new Vuex.Store((
tillstånd,
åtgärder,
mutationer
));
1. Modulerna
Vad ska du göra när butik.js
filen blir enorm och svår att arbeta med? Det finns faktiskt en riktigt cool Vuex-funktion - moduler. De är avsedda för att dela upp dina data i separata filer.
Tänk dig att du arbetar med en företagsapp, där du till exempel har några få datadomäner:
- user (hantera alla behörigheter och tillstånd),
- route-parametrar (hantera globala parametrar före förfrågningar till API),
- försäljning (för din SalesMegaChart-komponent som är synlig i ett månads-, kvartals- eller årssammanhang),
- order (synlig efter att ha klickat på SalesMegaChart-fältet).
...och kanske några till. Nu har du seriösa skäl att införa lite modularitet i din butik.
Först av allt, flytta butik.js
fil till en nyskapad butik/
och byt namn på den index.js
. Om du vill behålla allt förpackat i moduler kan du eventuellt ta bort tillstånd, åtgärder och mutationer från huvudfilen.
// butik/index.js
importera Vue från 'vue'
importera Vuex från 'vuex'
Vue.use(Vuex);
export default new Vuex.Store((
moduler: (
// moduler kommer att gå här
)
));
Sedan, bredvid filen `store/index.js`, skapar du den första modulen - `store/user.js`.
import ApiService från '../services/api.service';
const state = (
loggedIn: false,
loginError: null,
användare: null
);
const åtgärder = (
login: async (( commit ), data) (
försök (
const response = await ApiService.post('/login', data);
const ( user ) = response.data;
COMMIT("SAVE_USER", användare);
COMMIT("LOGIN_SUCCESS");
) catch (fel) (
commit("LOGIN_ERROR", fel);
)
)
);
mutationer = (
SAVE_USER (tillstånd, användare) (
state.user = användare;
),
LOGIN_SUCCESS (tillstånd) (
state.loggedIn = sant;
),
LOGIN_ERROR (tillstånd, fel) (
state.loginError = fel;
tillstånd.inloggad = false;
)
);
export const användare (
state,
åtgärder,
mutationer
)
Och nu, ladda den färdiga modulen i huvudfilen `store/index.js`:
importera Vue från 'vue'
importera Vuex från 'vuex'
import ( user ) från './user';
Vue.use(Vuex);
export default new Vuex.Store((
moduler: (
användare
)
));
Gratulerar, gratulerar! Nu har du en riktigt snygg butiksimplementering. Du kan också komma åt data från komponenten (t.ex, Användarprofil.vue
) så här:
<template>
<div class="user-profile">
<h2>(( användare.namn ))!</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. Namnrymder
Nu när du vet hur man använder moduler bör du också bekanta dig med Vuex:s namngivning. I det föregående steget skapade vi butik/användare.js
filen med användare modul.
Den datastruktur som definieras i användare.js
filen är åtkomlig från komponenter, men du kan se att alla användare data går direkt till den globala tillstånd
sammanhang, som här:
beräknad: mapState((
användare: tillstånd => tillstånd.användare
// användare: 'user' <-- alternativt sätt
))
När du definierar fler moduler kommer du förmodligen att bli förvirrad över vilket objekt som kommer från vilken modul. Då bör man använda namespaced modules och definiera dem på det här sättet:
export const användare (
namespaced: true, // <-- namespacing!
tillstånd,
åtgärder,
mutationer
)
Från och med nu kommer alla dina användare data (tillstånd
variabel från butik/användare.js
fil) kommer att hanteras under stat.användare
referens:
beräknad: mapState((
användare: tillstånd => tillstånd.användare.användare
// användare: 'user/user' <-- alternativt sätt
))
Några steg senare kan du för komponenten uppnå något liknande detta:
import ( mapActions ) från 'Vuex';
export standard (
namn: 'Instrumentpanel',
beräknad: mapState((
försäljning: 'försäljning/data',
order: 'order/data',
sortBy: 'order/sortBy',
inloggad: 'användare/loggadIn'
)),
methods: mapActions((
logout: 'användare/utloggning',
loadSales: "försäljning/belastning",
loadOrders: "beställningar/load
)),
skapad() (
if (this.loggedIn) (
loadSales();
laddaOrder();
)
)
)
Bravo! Bravo! Så fräscht, så rent... Men oroa dig inte, refaktorisering tar aldrig slut. Redo för nästa steg?
3. Kommunikation mellan moduler
I det första steget visade jag dig några åtgärder i användare modul:
const åtgärder = (
login: async (( commit ), data) (
försök (
const response = await ApiService.post('/login', data);
const ( user ) = response.data;
COMMIT("SAVE_USER", användare);
COMMIT("LOGIN_SUCCESS");
) catch (fel) (
commit("LOGIN_ERROR", fel);
)
)
);
I händelse av misslyckande lägger vi till inloggningsfel i vår butik - vad händer härnäst?
Här har vi några olika alternativ och valet beror på vilket alternativ som passar dina behov bäst. Det enklaste sättet använde v-if
direktivet, tack vare vilket ett felmeddelande kan visas om det uppstår ett fel i din butik.
<template>
<div class="dashboard">
<!-- dashboard component template -->
<div
v-if="error"
class="error-message"
> (( fel.meddelande )) </div>
</div>
</template>
<script> import ( mapActions ) from 'Vuex';
export default (
name: 'Dashboard',
computed: mapState((
error: "user/loginError"
))
)
</script>
Tänk dig återigen att du har många moduler och att varje försök/fångst
syntax genererar ett nytt fel i din butik. Självklart kommer du att missbruka DRY-regeln på det här sättet.
Hur kan du göra dina processer för felhantering mer generiska?
Låt oss definiera gemensam och lägga in lite logik där som skulle användas globalt.
// butik/gemensamt.js
const tillstånd = (
fel: []
);
const åtgärder = (
fel: (
root: true,
handler(( commit ), fel) (
commit("ERROR", fel);
)
)
),
mutationer = (
ERROR (tillstånd, fel) (
/* på det här sättet kommer vi att ha det nyaste felet högst upp i listan */
state.errors = [fel, ...state.errors];
))
);
export const common (
namespaced: true,
tillstånd,
mutationer
)
Nu kan vi anpassa användare (och även andra moduler):
försök (
// någon åtgärd
)fånga (fel) (
commit("common/ERROR", error, ( root: true ));
)
eller på ett mer elegant sätt, med hjälp av vår globala åtgärd:
try (
// någon åtgärd
) fånga (fel) (
dispatch("fel", fel);
)
Denna syntax för begå
och avsändande
samtal verkar självförklarande, men du kan läsa mer om dessa knep här.
När du har alla fel på ett ställe kan du enkelt ladda dem till din Instrumentpanel
komponent:
beräknat: mapState((
fel: 'vanliga/fel'
)),
klocka: (
/* detta kommer att anropas efter varje "common/ERROR"-mutation, där vi bara lägger till nya fel i lagret, ett efter ett */
errors() (
this.showErrorMessage(this.errors[0]);
)
)
Det tidigare exemplet med gemensam Modulhantering av fel är redan en effektiv lösning, men du kan gå ännu längre.
Som du kan se tittar vi på förändringar på vanliga/fel
array i butiken. I fall som dessa, när du behöver bestämma någon åtgärd för en viss mutation, kan du använda Vuex insticksmoduler eller till och med komponenter av högre ordning (HOC).
Jag kommer att diskutera plugins och HOC i nästa artikel. Under tiden tackar jag dig för att du läste den här artikeln och hoppas att du gillade de exempel vi har förberett.
Håll ögonen öppna och fortsätt att koda!
Läs mer om detta:
– Hur kan man förbättra Vue.js-appar? Några praktiska tips
– GraphQL: lärdomar från produktion
– Shopify, Spree eller Solidus? Kolla varför Ruby on Rails kan hjälpa dig att utveckla din e-handel