Frontend applicaties, vooral de complexere, moeten veel gegevens verwerken. Programmeurs introduceren verschillende ontwerppatronen om hun projecten leesbaar en onderhoudbaar te maken. In de meest voorkomende scenario's van een MVC willen we de gegevens scheiden van de visuele delen van de app.
Dat is de reden waarom opslaan zo nuttig is geworden. Het is aan jou of je React + Redux gebruikt of Vue + Vuex - het hoofddoel is hetzelfde, namelijk uw gegevens tegelijkertijd gestructureerd, toegankelijk en veilig houden.
In dit artikel laat ik je een paar voorbeelden zien van hoe je je Vuex schoon en efficiënt kunt houden.
Laten we voordat we beginnen aannemen dat:
- heb je enige ervaring met moderne JavaScript,
- weet je in principe wat Vue is en hoe je het moet gebruiken rekwisieten, berekend, enz,
- je bekend bent met Vuex (acties, mutaties, enz.) en je apps beter wilt maken.
Vuexzoals de meerderheid van de kern Vue projectenis vrij goed gedocumenteerd en je kunt veel handige hacks vinden in de officiële documenten. We hebben er wat essentiële informatie voor je uitgehaald.
Een basisimplementatie van een Vuex-winkel ziet er als volgt uit:
// main.js
importeer Vue uit 'vue'.
importeer Vuex uit 'vuex'.
importeer App uit "./App";
Vue.use(Vuex)
const store = nieuwe Vuex.Store(
toestand: (
gegevens: nul;
),
acties: (
someAction: (( commit ), gegevens) (
commit("SOME_MUTATION", gegevens);
)
),
mutaties: (
SOME_MUTATION (status, gegevens) (
state.data = data;
)
))
));
nieuwe Vue(
el: "#app",
render: h => h(App),
opslaan:
));
Als je app groter wordt, moet je meestal routing, enkele globale richtlijnen, plugins, enz. toepassen. Dit maakt de main.js
bestand veel langer en moeilijker te lezen. Het is een goede gewoonte om de opslag in een extern bestand te bewaren, zoals hier:
// winkel.js
importeer Vue uit 'vue'.
importeer Vuex uit 'vuex'.
Vue.use(Vuex);
const state = (
data: null;
);
const acties = (
someAction: (( commit ), data) (
commit("SOME_MUTATION", gegevens);
)
);
const mutaties = (
SOME_MUTATION (status, gegevens) (
state.data = data;
)
);
export standaard nieuwe Vuex.Store(
status,
acties,
mutaties
));
1. Modules
Wat moet u doen als de winkel.js
bestand wordt enorm en moeilijk om aan te werken? Eigenlijk is er een echt coole Vuex functie - modules. Ze zijn bedoeld om je gegevens op te splitsen in afzonderlijke bestanden.
Stel je voor dat je werkt aan een of andere bedrijfsapp, waarin je bijvoorbeeld weinig gegevensdomeinen hebt:
- gebruiker (alle machtigingen en rechten beheren),
- routeparameters (beheer globale parameters voor verzoeken aan API),
- verkoop (voor je SalesMegaChart-component die zichtbaar is in een maandelijkse/kwartaalelijkse/jaarlijkse context),
- orders (zichtbaar nadat je op de SalesMegaChart-balk hebt geklikt).
...en misschien nog wel een paar meer. Nu heb je serieuze redenen om wat modulariteit in je winkel te introduceren.
Verplaats eerst de winkel.js
bestand naar een nieuw aangemaakt winkel/
map en hernoem deze index.js
. Optioneel, als u alles verpakt in modules wilt houden, verwijdert u staat, acties en mutaties uit het hoofdbestand.
// winkel/index.js
importeer Vue uit 'vue'.
importeer Vuex uit 'vuex'.
Vue.use(Vuex);
export standaard nieuwe Vuex.Store(
modules: (
// modules komen hier
)
));
Maak dan, naast het `store/index.js` bestand, de eerste module - `store/user.js`.
importeer ApiService uit '../services/api.service';
const state = (
ingelogd: false,
loginError: null,
gebruiker: nul
);
const acties = (
login: async (( commit ), data) (
proberen (
const response = await ApiService.post('/login', data);
const ( gebruiker ) = response.data;
COMMIT("SAVE_USER", gebruiker);
COMMIT("LOGIN_SUCCESS");
) vang (fout) (
commit("LOGIN_ERROR", fout);
)
)
);
constaties = (
SAVE_USER (status, gebruiker) (
state.user = user;
),
LOGIN_SUCCESS (state) (
state.loggedIn = true;
),
LOGIN_ERROR (status, fout) (
state.loginError = error;
state.loggedIn = false;
)
);
export const user (
status,
acties,
mutaties
)
En laad nu de module die klaar is in het hoofdbestand `store/index.js`:
import Vue uit 'vue'
importeer Vuex van 'vuex'.
importeer ( user ) uit './user';
Vue.use(Vuex);
export standaard nieuwe Vuex.Store(
modules: (
gebruiker
)
));
Gefeliciteerd! Nu heb je een mooie winkelimplementatie. Je kunt ook toegang krijgen tot de gegevens van de component (bijv, Gebruikersprofiel.vue
) als volgt:
<template>
<div class="user-profile">
<h2>(( user.name ))!</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. Naamruimten
Nu je weet hoe je modules moet gebruiken, moet je ook vertrouwd raken met de Vuex's namespacing. In de vorige stap hebben we de winkel/gebruiker.js
bestand met de gebruiker module.
De gegevensstructuur gedefinieerd in de gebruiker.js
bestand toegankelijk is vanuit componenten, maar je kunt zien dat alle gebruiker gegevens gaan direct naar de globale staat
context, zoals hier:
berekend: mapState(
gebruiker: staat => staat.gebruiker
// gebruiker: 'user' <-- alternatieve manier
))
Als je meer modules definieert, raak je waarschijnlijk in de war over welk object uit welke module komt. Dan moet je namespaced modules gebruiken en ze op deze manier definiëren:
export const user (
namespaced: true, // <-- namespacing!
status,
acties,
mutaties
)
Vanaf nu zijn al je gebruiker gegevens (staat
variabele van winkel/gebruiker.js
bestand) wordt afgehandeld onder de staat.gebruiker
referentie:
berekend: mapState(
gebruiker: staat => staat.gebruiker.gebruiker
// gebruiker: 'user/user' <-- alternatieve manier
))
Een paar stappen later kun je voor de component iets als dit bereiken:
import ( mapActions ) from 'Vuex';
export default (
naam: 'Dashboard',
berekend: mapState(
verkopen: "verkopen/gegevens
orders: "orders/data
sortBy: "orders/sortBy",
ingelogd: "gebruiker/ingelogd
)),
methoden: mapActions(
uitloggen: 'user/logout',
loadSales: "verkoop/laden",
loadOrders: "orders/laden
)),
aangemaakt() (
als (this.loggedIn) (
loadSales();
loadOrders();
)
)
)
Bravo! Zo fris, zo schoon... Maar maak je geen zorgen, refactoring eindigt nooit. Klaar voor de volgende stappen?
3. Communicatie tussen modules
In de eerste stap liet ik je wat actie zien in de gebruiker module:
const acties = (
login: async (( commit ), data) (
proberen (
const response = await ApiService.post('/login', data);
const ( gebruiker ) = response.data;
COMMIT("SAVE_USER", gebruiker);
COMMIT("LOGIN_SUCCESS");
) vang (fout) (
commit("LOGIN_ERROR", fout);
)
)
);
Als het niet lukt, voegen we een aanmeldingsfout toe aan onze winkel - wat nu?
Hier hebben we een paar opties en de keuze hangt af van welke optie het beste bij je past. De eenvoudigste manier gebruikt de v-if
directive, waarmee een foutmelding kan worden weergegeven als er een fout optreedt in je winkel.
<template>
<div class="dashboard">
<!-- dashboard component template -->
<div
v-if="error"
class="error-message"
> (( error.message )) </div>
</div>
</template>
<script> import ( mapActions ) from 'Vuex';
export default (
name: 'Dashboard',
computed: mapState((
error: "user/loginError"
))
)
</script>
Stel je weer voor dat je veel modules hebt en elke try/catch
syntax genereert een nieuwe fout in je winkel. Het is duidelijk dat je op deze manier misbruik maakt van de DRY-regel.
Hoe kunt u uw foutafhandelingsprocessen generieker maken?
Laten we de gewoon module en daar wat logica in stoppen die wereldwijd wordt gebruikt.
// winkel/gemeenschappelijk.js
const status = (
fouten: []
);
const acties = (
fout: (
root: true,
handler(( commit ), fout) (
commit("ERROR", fout);
)
)
),
const mutaties = (
ERROR (status, fout) (
/* op deze manier krijgen we de nieuwste fout bovenaan de lijst */
state.errors = [error, ...state.errors];
))
);
export const common (
namespaced: true,
toestand,
mutaties
)
Nu kunnen we de gebruiker module (en ook andere modules):
probeer (
// een actie
)catch (error) (
commit("common/ERROR", error, ( root: true ));
)
of op een elegantere manier, met behulp van onze globale actie:
try (
// een actie
) vang (fout) (
dispatch("fout", fout);
)
Deze syntaxis van vastleggen
en verzenden
Gesprekken lijken vanzelfsprekend, maar je kunt meer lezen over deze trucs hier.
Als je alle fouten op één plek hebt, kun je ze eenvoudig laden naar je Dashboard
component:
berekend: mapState((
fouten: "gemeenschappelijk/fouten
)),
watch: (
/* dit wordt aangeroepen na elke "common/ERROR"-mutatie, waarbij we alleen nieuwe fouten één voor één aan de opslag toevoegen */
errors() (
this.showErrorMessage(this.errors[0]);
)
)
Het vorige voorbeeld met de gewoon module voor het afhandelen van fouten is al een efficiënte oplossing, maar je kunt nog verder gaan.
Zoals je kunt zien, kijken we naar veranderingen op de gemeenschappelijk/fouten
array in de winkel. In gevallen als deze, wanneer je een actie op een bepaalde mutatie moet bepalen, kun je het volgende gebruiken Vuex aansluitingen of zelfs Hogere Orde Componenten (HOC).
Ik zal de plugins en HOC's in het volgende artikel bespreken. Ondertussen bedankt voor het lezen van dit artikel, hopelijk heb je genoten van de voorbeelden die we hebben voorbereid.
Blijf op de hoogte en blijf coderen!
Lees meer:
– Hoe kun je Vue.js-apps verbeteren? Enkele praktische tips
– GraphQL: geleerde lessen in productie
– Shopify, Spree of Solidus? Check waarom Ruby on Rails jou kan helpen met het ontwikkelen van je e-commerce