|
|
1 month ago | |
|---|---|---|
| .. | ||
| README.md | 1 month ago | |
| assignment.md | 1 month ago | |
README.md
Een bankapp bouwen Deel 4: Concepten van State Management
Quiz voor de les
Introductie
State management is als het navigatiesysteem op het Voyager-ruimteschip – als alles soepel werkt, merk je nauwelijks dat het er is. Maar als er iets misgaat, kan het het verschil maken tussen het bereiken van de interstellaire ruimte en verloren raken in de kosmische leegte. In webontwikkeling vertegenwoordigt de state alles wat je applicatie moet onthouden: gebruikersloginstatus, formuliergegevens, navigatiegeschiedenis en tijdelijke interface-statussen.
Nu je bankapp is geëvolueerd van een eenvoudige inlogformulier naar een meer geavanceerde applicatie, ben je waarschijnlijk enkele veelvoorkomende uitdagingen tegengekomen. Vernieuw de pagina en gebruikers worden onverwacht uitgelogd. Sluit de browser en alle voortgang verdwijnt. Probeer een probleem op te lossen en je zoekt door meerdere functies die allemaal op verschillende manieren dezelfde gegevens wijzigen.
Dit zijn geen tekenen van slecht programmeren – het zijn de natuurlijke groeipijnen die optreden wanneer applicaties een bepaalde complexiteitsdrempel bereiken. Elke ontwikkelaar wordt met deze uitdagingen geconfronteerd wanneer hun apps overgaan van "proof of concept" naar "productieklaar."
In deze les implementeren we een gecentraliseerd state management systeem dat je bankapp transformeert in een betrouwbare, professionele applicatie. Je leert gegevensstromen voorspelbaar te beheren, gebruikerssessies op de juiste manier te behouden en de soepele gebruikerservaring te creëren die moderne webapplicaties vereisen.
Vereisten
Voordat je je verdiept in de concepten van state management, moet je ervoor zorgen dat je ontwikkelomgeving goed is ingesteld en dat de basis van je bankapp in orde is. Deze les bouwt direct voort op de concepten en code uit de eerdere delen van deze serie.
Zorg ervoor dat je de volgende componenten klaar hebt voordat je verder gaat:
Benodigdheden:
- Voltooi de les over gegevens ophalen - je app moet succesvol accountgegevens laden en weergeven
- Installeer Node.js op je systeem om de backend-API te draaien
- Start de server-API lokaal om accountgegevens te verwerken
Test je omgeving:
Controleer of je API-server correct werkt door dit commando uit te voeren in een terminal:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
Wat dit commando doet:
- Verstuurt een GET-verzoek naar je lokale API-server
- Test de verbinding en controleert of de server reageert
- Geeft de API-versie-informatie terug als alles correct werkt
Diagnosticeer de huidige state-problemen
Net als Sherlock Holmes die een plaats delict onderzoekt, moeten we precies begrijpen wat er gebeurt in onze huidige implementatie voordat we het mysterie van verdwijnende gebruikerssessies kunnen oplossen.
Laten we een eenvoudig experiment uitvoeren dat de onderliggende uitdagingen van state management onthult:
🧪 Probeer deze diagnostische test:
- Log in op je bankapp en navigeer naar het dashboard
- Vernieuw de browserpagina
- Observeer wat er gebeurt met je loginstatus
Als je wordt doorgestuurd naar het inlogscherm, heb je het klassieke probleem van state-persistentie ontdekt. Dit gedrag treedt op omdat onze huidige implementatie gebruikersgegevens opslaat in JavaScript-variabelen die bij elke paginalading worden gereset.
Huidige implementatieproblemen:
De eenvoudige account-variabele uit onze vorige les veroorzaakt drie belangrijke problemen die zowel de gebruikerservaring als de onderhoudbaarheid van de code beïnvloeden:
| Probleem | Technische oorzaak | Impact op gebruiker |
|---|---|---|
| Sessieverlies | Pagina vernieuwen wist JavaScript-variabelen | Gebruikers moeten vaak opnieuw inloggen |
| Verspreide updates | Meerdere functies wijzigen de state direct | Debuggen wordt steeds moeilijker |
| Onvolledige opruiming | Uitloggen wist niet alle state-referenties | Mogelijke beveiligings- en privacyproblemen |
De architecturale uitdaging:
Net als het compartimentontwerp van de Titanic dat robuust leek totdat meerdere compartimenten tegelijkertijd overstroomden, zal het afzonderlijk oplossen van deze problemen de onderliggende architecturale uitdaging niet aanpakken. We hebben een uitgebreide oplossing voor state management nodig.
💡 Wat proberen we hier eigenlijk te bereiken?
State management draait eigenlijk om het oplossen van twee fundamentele puzzels:
- Waar zijn mijn gegevens?: Bijhouden welke informatie we hebben en waar die vandaan komt
- Is iedereen op dezelfde pagina?: Zorgen dat wat gebruikers zien overeenkomt met wat er daadwerkelijk gebeurt
Ons actieplan:
In plaats van achter de feiten aan te lopen, gaan we een gecentraliseerd state management systeem creëren. Denk eraan als één echt georganiseerd persoon die verantwoordelijk is voor alle belangrijke zaken:
Begrijpen van deze gegevensstroom:
- Centraliseert alle applicatiestate op één locatie
- Routet alle state-wijzigingen via gecontroleerde functies
- Zorgt ervoor dat de UI gesynchroniseerd blijft met de huidige state
- Biedt een duidelijk, voorspelbaar patroon voor gegevensbeheer
💡 Professioneel inzicht: Deze les richt zich op fundamentele concepten. Voor complexe applicaties bieden bibliotheken zoals Redux meer geavanceerde functies voor state management. Het begrijpen van deze kernprincipes helpt je om elke state management-bibliotheek onder de knie te krijgen.
⚠️ Geavanceerd onderwerp: We behandelen geen automatische UI-updates die worden geactiveerd door state-wijzigingen, omdat dit concepten van Reactive Programming omvat. Beschouw dit als een uitstekende volgende stap in je leertraject!
Taak: Centraliseer de structuur van de state
Laten we beginnen met het transformeren van ons verspreide state management naar een gecentraliseerd systeem. Deze eerste stap legt de basis voor alle verbeteringen die volgen.
Stap 1: Maak een gecentraliseerd state-object
Vervang de eenvoudige account-verklaring:
let account = null;
Door een gestructureerd state-object:
let state = {
account: null
};
Waarom deze verandering belangrijk is:
- Centraliseert alle applicatiegegevens op één locatie
- Bereidt de structuur voor om later meer state-eigenschappen toe te voegen
- Creëert een duidelijke scheiding tussen state en andere variabelen
- Legt een patroon vast dat schaalbaar is naarmate je app groeit
Stap 2: Update state-toegangspatronen
Update je functies om de nieuwe state-structuur te gebruiken:
In de functies register() en login(), vervang:
account = ...
Door:
state.account = ...
In de functie updateDashboard(), voeg deze regel toe bovenaan:
const account = state.account;
Wat deze updates bereiken:
- Behoudt bestaande functionaliteit terwijl de structuur wordt verbeterd
- Bereidt je code voor op meer geavanceerd state management
- Creëert consistente patronen voor toegang tot state-gegevens
- Legt de basis voor gecentraliseerde state-updates
💡 Opmerking: Deze refactoring lost onze problemen niet onmiddellijk op, maar creëert de essentiële basis voor de krachtige verbeteringen die volgen!
Gecontroleerde state-updates implementeren
Met onze state gecentraliseerd, is de volgende stap het opzetten van gecontroleerde mechanismen voor gegevenswijzigingen. Deze aanpak zorgt voor voorspelbare state-wijzigingen en gemakkelijker debuggen.
Het kernprincipe lijkt op luchtverkeersleiding: in plaats van meerdere functies toe te staan om de state onafhankelijk te wijzigen, leiden we alle wijzigingen door een enkele, gecontroleerde functie. Dit patroon biedt duidelijk toezicht op wanneer en hoe gegevens worden gewijzigd.
Immutable State Management:
We behandelen ons state-object als immutable, wat betekent dat we het nooit direct wijzigen. In plaats daarvan creëert elke wijziging een nieuw state-object met de bijgewerkte gegevens.
Hoewel deze aanpak in eerste instantie misschien inefficiënt lijkt in vergelijking met directe wijzigingen, biedt het aanzienlijke voordelen voor debuggen, testen en het behouden van voorspelbaarheid van de applicatie.
Voordelen van immutable state management:
| Voordeel | Beschrijving | Impact |
|---|---|---|
| Voorspelbaarheid | Wijzigingen gebeuren alleen via gecontroleerde functies | Makkelijker te debuggen en testen |
| Geschiedenis bijhouden | Elke state-wijziging creëert een nieuw object | Maakt undo/redo-functionaliteit mogelijk |
| Voorkomen van bijwerkingen | Geen onbedoelde wijzigingen | Voorkomt mysterieuze bugs |
| Prestatieoptimalisatie | Makkelijk te detecteren wanneer de state daadwerkelijk is gewijzigd | Maakt efficiënte UI-updates mogelijk |
JavaScript Immutability met Object.freeze():
JavaScript biedt Object.freeze() om objectwijzigingen te voorkomen:
const immutableState = Object.freeze({ account: userData });
// Any attempt to modify immutableState will throw an error
Wat hier gebeurt:
- Voorkomt directe toewijzing of verwijdering van eigenschappen
- Geeft uitzonderingen als er pogingen tot wijzigingen worden gedaan
- Zorgt ervoor dat state-wijzigingen via gecontroleerde functies moeten gaan
- Creëert een duidelijke afspraak over hoe de state kan worden bijgewerkt
💡 Verdieping: Lees meer over het verschil tussen shallow en deep immutable objecten in de MDN-documentatie. Het begrijpen van dit onderscheid is cruciaal voor complexe state-structuren.
Taak
Laten we een nieuwe functie updateState() maken:
function updateState(property, newData) {
state = Object.freeze({
...state,
[property]: newData
});
}
In deze functie maken we een nieuw state-object en kopiëren gegevens van de vorige state met behulp van de spread (...) operator. Vervolgens overschrijven we een specifieke eigenschap van het state-object met de nieuwe gegevens met behulp van de bracket notatie [property] voor toewijzing. Ten slotte vergrendelen we het object om wijzigingen te voorkomen met Object.freeze(). Voor nu hebben we alleen de eigenschap account opgeslagen in de state, maar met deze aanpak kun je zoveel eigenschappen toevoegen als je nodig hebt in de state.
We zullen ook de state-initialisatie bijwerken om ervoor te zorgen dat de initiële state ook wordt bevroren:
let state = Object.freeze({
account: null
});
Daarna, update de register-functie door de toewijzing state.account = result; te vervangen door:
updateState('account', result);
Doe hetzelfde met de login-functie, vervang state.account = data; door:
updateState('account', data);
We nemen nu de kans om het probleem op te lossen waarbij accountgegevens niet worden gewist wanneer de gebruiker op Logout klikt.
Maak een nieuwe functie logout():
function logout() {
updateState('account', null);
navigate('/login');
}
In updateDashboard(), vervang de redirect return navigate('/login'); door return logout();
Probeer een nieuw account te registreren, uit te loggen en opnieuw in te loggen om te controleren of alles nog steeds correct werkt.
Tip: je kunt alle state-wijzigingen bekijken door
console.log(state)onderaanupdateState()toe te voegen en de console in je browserontwikkeltools te openen.
Gegevenspersistentie implementeren
Het probleem van sessieverlies dat we eerder hebben geïdentificeerd, vereist een persistentieoplossing die de gebruikersstate behoudt over browsersessies. Dit transformeert onze applicatie van een tijdelijke ervaring naar een betrouwbare, professionele tool.
Denk aan hoe atoomklokken nauwkeurige tijd behouden, zelfs tijdens stroomstoringen, door kritieke state op te slaan in niet-vluchtig geheugen. Op dezelfde manier hebben webapplicaties persistente opslagmechanismen nodig om essentiële gebruikersgegevens te behouden over browsersessies en paginavernieuwingen.
Strategische vragen voor gegevenspersistentie:
Voordat je persistentie implementeert, overweeg deze kritieke factoren:
| Vraag | Context van de bankapp | Impact van beslissing |
|---|---|---|
| Zijn de gegevens gevoelig? | Rekeningbalans, transactiegeschiedenis | Kies veilige opslagmethoden |
| Hoe lang moet het blijven bestaan? | Loginstatus vs. tijdelijke UI-voorkeuren | Selecteer geschikte opslagduur |
| Heeft de server het nodig? | Authenticatietokens vs. UI-instellingen | Bepaal delingsvereisten |
Browseropslagopties:
Moderne browsers bieden verschillende opslagmechanismen, elk ontworpen voor verschillende gebruiksscenario's:
Primaire opslag-API's:
-
localStorage: Persistente Key/Value-opslag- Behoudt gegevens over browsersessies heen
- Overleeft browserherstarts en computerreboots
- Gebonden aan het specifieke website-domein
- Perfect voor gebruikersvoorkeuren en loginstatussen
-
sessionStorage: Tijdelijke sessieopslag- Werkt identiek aan localStorage tijdens actieve sessies
- Wist automatisch wanneer het browsertabblad wordt gesloten
- Ideaal voor tijdelijke gegevens die niet moeten blijven bestaan
-
HTTP-cookies: Servergedeelde opslag
- Automatisch verzonden met elk serververzoek
- Perfect voor authenticatie tokens
- Beperkt in grootte en kan prestaties beïnvloeden
Vereiste gegevensserialisatie:
Zowel localStorage als sessionStorage slaan alleen strings op:
// Convert objects to JSON strings for storage
const accountData = { user: 'john', balance: 150 };
localStorage.setItem('account', JSON.stringify(accountData));
// Parse JSON strings back to objects when retrieving
const savedAccount = JSON.parse(localStorage.getItem('account'));
Begrijpen van serialisatie:
- Converteert JavaScript-objecten naar JSON-strings met
JSON.stringify() - Reconstrueert objecten uit JSON met
JSON.parse() - Behandelt automatisch complexe geneste objecten en arrays
- Faalt bij functies, ongedefinieerde waarden en circulaire referenties
💡 Geavanceerde Optie: Voor complexe offline applicaties met grote datasets, overweeg de
IndexedDBAPI. Dit biedt een volledige client-side database, maar vereist een complexere implementatie.
Taak: Implementeer localStorage Persistentie
Laten we een persistent opslagmechanisme implementeren zodat gebruikers ingelogd blijven totdat ze expliciet uitloggen. We gebruiken localStorage om accountgegevens op te slaan tussen browsersessies.
Stap 1: Definieer Opslagconfiguratie
const storageKey = 'savedAccount';
Wat deze constante biedt:
- Creëert een consistente identifier voor onze opgeslagen gegevens
- Voorkomt typefouten in opslagkeys
- Maakt het eenvoudig om de opslagkey te wijzigen indien nodig
- Volgt best practices voor onderhoudbare code
Stap 2: Voeg Automatische Persistentie Toe
Voeg deze regel toe aan het einde van de updateState() functie:
localStorage.setItem(storageKey, JSON.stringify(state.account));
Uitleg van wat hier gebeurt:
- Converteert het accountobject naar een JSON-string voor opslag
- Slaat de gegevens op met onze consistente opslagkey
- Wordt automatisch uitgevoerd wanneer er statuswijzigingen plaatsvinden
- Zorgt ervoor dat opgeslagen gegevens altijd gesynchroniseerd zijn met de huidige status
💡 Architectuurvoordeel: Omdat we alle statusupdates hebben gecentraliseerd via
updateState(), was het toevoegen van persistentie slechts één regel code. Dit toont de kracht van goede architectonische beslissingen!
Stap 3: Herstel Status bij App-opstart
Maak een initialisatiefunctie om opgeslagen gegevens te herstellen:
function init() {
const savedAccount = localStorage.getItem(storageKey);
if (savedAccount) {
updateState('account', JSON.parse(savedAccount));
}
// Our previous initialization code
window.onpopstate = () => updateRoute();
updateRoute();
}
init();
Begrip van het initialisatieproces:
- Haalt eerder opgeslagen accountgegevens op uit localStorage
- Parseert de JSON-string terug naar een JavaScript-object
- Update de status met behulp van onze gecontroleerde updatefunctie
- Herstelt automatisch de sessie van de gebruiker bij het laden van de pagina
- Wordt uitgevoerd voordat route-updates plaatsvinden om ervoor te zorgen dat de status beschikbaar is
Stap 4: Optimaliseer de Standaardroute
Werk de standaardroute bij om gebruik te maken van persistentie:
In updateRoute(), vervang:
// Replace: return navigate('/login');
return navigate('/dashboard');
Waarom deze wijziging logisch is:
- Benut ons nieuwe persistentiesysteem effectief
- Laat het dashboard authenticatiecontroles uitvoeren
- Leidt automatisch door naar inloggen als er geen opgeslagen sessie is
- Creëert een meer naadloze gebruikerservaring
Testen van je Implementatie:
- Log in op je bankapp
- Vernieuw de browserpagina
- Controleer of je ingelogd blijft en op het dashboard blijft
- Sluit en heropen je browser
- Navigeer terug naar je app en bevestig dat je nog steeds ingelogd bent
🎉 Prestatie Behaald: Je hebt succesvol een persistent statusbeheersysteem geïmplementeerd! Je app gedraagt zich nu als een professionele webapplicatie.
Balans tussen Persistentie en Gegevensactualiteit
Ons persistentiesysteem behoudt succesvol gebruikerssessies, maar introduceert een nieuwe uitdaging: verouderde gegevens. Wanneer meerdere gebruikers of applicaties dezelfde servergegevens wijzigen, worden lokaal gecachte gegevens verouderd.
Deze situatie lijkt op Vikingnavigators die zowel opgeslagen sterrenkaarten als actuele waarnemingen van de sterrenhemel gebruikten. De kaarten boden consistentie, maar navigators hadden actuele waarnemingen nodig om rekening te houden met veranderende omstandigheden. Evenzo heeft onze applicatie zowel persistente gebruikersstatus als actuele servergegevens nodig.
🧪 Het Probleem van Gegevensveroudering Ontdekken:
- Log in op het dashboard met het
testaccount - Voer dit commando uit in een terminal om een transactie vanuit een andere bron te simuleren:
curl --request POST \
--header "Content-Type: application/json" \
--data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
http://localhost:5000/api/accounts/test/transactions
- Vernieuw je dashboardpagina in de browser
- Observeer of je de nieuwe transactie ziet
Wat deze test aantoont:
- Laat zien hoe localStorage "verouderd" kan raken
- Simuleert realistische scenario's waarin gegevens buiten je app veranderen
- Toont de spanning tussen persistentie en gegevensactualiteit
De Uitdaging van Verouderde Gegevens:
| Probleem | Oorzaak | Impact op Gebruiker |
|---|---|---|
| Verouderde Gegevens | localStorage verloopt nooit automatisch | Gebruikers zien verouderde informatie |
| Serverwijzigingen | Andere apps/gebruikers wijzigen dezelfde gegevens | Inconsistente weergaven tussen platforms |
| Cache vs. Realiteit | Lokale cache komt niet overeen met serverstatus | Slechte gebruikerservaring en verwarring |
Oplossingsstrategie:
We implementeren een "verversen bij laden"-patroon dat de voordelen van persistentie in balans brengt met de noodzaak van actuele gegevens. Deze aanpak behoudt de soepele gebruikerservaring en zorgt tegelijkertijd voor gegevensnauwkeurigheid.
Taak: Implementeer Gegevensverversingssysteem
We maken een systeem dat automatisch actuele gegevens van de server ophaalt terwijl we de voordelen van ons persistente statusbeheer behouden.
Stap 1: Maak Accountgegevens-Updater
async function updateAccountData() {
const account = state.account;
if (!account) {
return logout();
}
const data = await getAccount(account.user);
if (data.error) {
return logout();
}
updateState('account', data);
}
Begrip van de logica van deze functie:
- Controleert of een gebruiker momenteel is ingelogd (state.account bestaat)
- Leidt door naar uitloggen als er geen geldige sessie is
- Haalt actuele accountgegevens op van de server met behulp van de bestaande
getAccount()functie - Handelt serverfouten netjes af door ongeldige sessies uit te loggen
- Update de status met actuele gegevens via ons gecontroleerde updatesysteem
- Activeert automatische localStorage-persistentie via de
updateState()functie
Stap 2: Maak Dashboard Verversingshandler
async function refresh() {
await updateAccountData();
updateDashboard();
}
Wat deze verversingsfunctie bereikt:
- Coördineert het gegevensverversings- en UI-updateproces
- Wacht tot actuele gegevens zijn geladen voordat de weergave wordt bijgewerkt
- Zorgt ervoor dat het dashboard de meest actuele informatie toont
- Behoudt een duidelijke scheiding tussen gegevensbeheer en UI-updates
Stap 3: Integreer met Routesysteem
Werk je routeconfiguratie bij om automatisch te verversen:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: refresh }
};
Hoe deze integratie werkt:
- Voert de verversingsfunctie uit elke keer dat de dashboardroute wordt geladen
- Zorgt ervoor dat actuele gegevens altijd worden weergegeven wanneer gebruikers naar het dashboard navigeren
- Behoudt de bestaande routestructuur terwijl gegevensactualiteit wordt toegevoegd
- Biedt een consistent patroon voor route-specifieke initialisatie
Testen van je Gegevensverversingssysteem:
- Log in op je bankapp
- Voer het eerder genoemde curl-commando uit om een nieuwe transactie te maken
- Vernieuw je dashboardpagina of navigeer weg en terug
- Controleer of de nieuwe transactie direct verschijnt
🎉 Perfecte Balans Bereikt: Je app combineert nu de soepele ervaring van persistente status met de nauwkeurigheid van actuele servergegevens!
GitHub Copilot Agent Uitdaging 🚀
Gebruik de Agent-modus om de volgende uitdaging te voltooien:
Beschrijving: Implementeer een uitgebreid statusbeheersysteem met ongedaan maken/herstellen-functionaliteit voor de bankapp. Deze uitdaging helpt je geavanceerde concepten van statusbeheer te oefenen, waaronder het bijhouden van statusgeschiedenis, onveranderlijke updates en synchronisatie van de gebruikersinterface.
Prompt: Maak een verbeterd statusbeheersysteem dat omvat: 1) Een statusgeschiedenis-array die alle eerdere statussen bijhoudt, 2) Ongedaan maken- en herstellenfuncties die naar eerdere statussen kunnen terugkeren, 3) UI-knoppen voor ongedaan maken/herstellen op het dashboard, 4) Een maximale geschiedenisgrens van 10 statussen om geheugenproblemen te voorkomen, en 5) Correct opruimen van geschiedenis wanneer de gebruiker uitlogt. Zorg ervoor dat de ongedaan maken/herstellen-functionaliteit werkt met wijzigingen in het accountsaldo en blijft bestaan na browserverversingen.
Lees meer over agent mode hier.
🚀 Uitdaging: Opslagoptimalisatie
Je implementatie beheert nu gebruikerssessies, gegevensverversing en statusbeheer effectief. Overweeg echter of onze huidige aanpak opslag efficiënt balanceert met functionaliteit.
Net als schaakmeesters die onderscheid maken tussen essentiële stukken en inwisselbare pionnen, vereist effectief statusbeheer het identificeren van welke gegevens moeten worden behouden versus welke altijd vers van de server moeten komen.
Optimalisatieanalyse:
Evalueer je huidige localStorage-implementatie en overweeg deze strategische vragen:
- Wat is de minimale informatie die nodig is om gebruikersauthenticatie te behouden?
- Welke gegevens veranderen zo vaak dat lokale caching weinig voordeel biedt?
- Hoe kan opslagoptimalisatie de prestaties verbeteren zonder de gebruikerservaring te verslechteren?
Implementatiestrategie:
- Identificeer de essentiële gegevens die moeten worden behouden (waarschijnlijk alleen gebruikersidentificatie)
- Pas je localStorage-implementatie aan om alleen kritieke sessiegegevens op te slaan
- Zorg ervoor dat actuele gegevens altijd van de server worden geladen bij dashboardbezoeken
- Test of je geoptimaliseerde aanpak dezelfde gebruikerservaring behoudt
Geavanceerde Overweging:
- Vergelijk de afwegingen tussen het opslaan van volledige accountgegevens versus alleen authenticatietokens
- Documenteer je beslissingen en redeneringen voor toekomstige teamleden
Deze uitdaging helpt je denken als een professionele ontwikkelaar die zowel de gebruikerservaring als de efficiëntie van de applicatie in overweging neemt. Neem de tijd om te experimenteren met verschillende benaderingen!
Quiz na de Les
Opdracht
Implementeer "Transactie toevoegen" dialoogvenster
Hier is een voorbeeldresultaat na het voltooien van de opdracht:
Disclaimer:
Dit document is vertaald met behulp van de AI-vertalingsservice Co-op Translator. Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in de oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor kritieke informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor eventuele misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.

