You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/no/7-bank-project/4-state-management/README.md

27 KiB

Bygg en bankapp del 4: Konsepter for tilstandshåndtering

Quiz før forelesning

Quiz før forelesning

Introduksjon

Tilstandshåndtering er som navigasjonssystemet på Voyager-romfartøyet når alt fungerer som det skal, merker du knapt at det er der. Men når ting går galt, kan det være forskjellen mellom å nå interstellart rom og å drive viljeløst i det kosmiske tomrommet. I webutvikling representerer tilstand alt applikasjonen din trenger å huske: brukerens innloggingsstatus, skjemadata, navigasjonshistorikk og midlertidige grensesnittilstander.

Etter hvert som bankappen din har utviklet seg fra et enkelt innloggingsskjema til en mer sofistikert applikasjon, har du sannsynligvis støtt på noen vanlige utfordringer. Oppdater siden, og brukerne blir uventet logget ut. Lukk nettleseren, og all fremgang forsvinner. Feilsøk et problem, og du leter gjennom flere funksjoner som alle endrer de samme dataene på forskjellige måter.

Dette er ikke tegn på dårlig koding det er de naturlige voksesmertene som oppstår når applikasjoner når et visst kompleksitetsnivå. Hver utvikler møter disse utfordringene når appene deres går fra "proof of concept" til "produksjonsklar."

I denne leksjonen skal vi implementere et sentralisert system for tilstandshåndtering som forvandler bankappen din til en pålitelig, profesjonell applikasjon. Du vil lære å håndtere dataflyt på en forutsigbar måte, opprettholde brukerøkter riktig og skape den jevne brukeropplevelsen som moderne webapplikasjoner krever.

Forutsetninger

Før du dykker ned i konseptene for tilstandshåndtering, må du ha utviklingsmiljøet ditt riktig satt opp og grunnlaget for bankappen din på plass. Denne leksjonen bygger direkte på konseptene og koden fra tidligere deler av denne serien.

Sørg for at du har følgende komponenter klare før du fortsetter:

Nødvendig oppsett:

  • Fullfør leksjonen om datahenting - appen din bør laste og vise kontodata korrekt
  • Installer Node.js på systemet ditt for å kjøre backend-API
  • Start server-API lokalt for å håndtere kontodataoperasjoner

Test miljøet ditt:

Bekreft at API-serveren din kjører korrekt ved å utføre denne kommandoen i en terminal:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

Hva denne kommandoen gjør:

  • Sender en GET-forespørsel til din lokale API-server
  • Tester tilkoblingen og bekrefter at serveren svarer
  • Returnerer API-versjonsinformasjon hvis alt fungerer som det skal

Diagnostisering av nåværende tilstandsproblemer

Som Sherlock Holmes som undersøker en åsted, må vi forstå nøyaktig hva som skjer i vår nåværende implementering før vi kan løse mysteriet med forsvinnende brukerøkter.

La oss gjennomføre et enkelt eksperiment som avslører de underliggende utfordringene med tilstandshåndtering:

🧪 Prøv denne diagnostiske testen:

  1. Logg inn på bankappen din og naviger til dashbordet
  2. Oppdater nettlesersiden
  3. Observer hva som skjer med innloggingsstatusen din

Hvis du blir omdirigert tilbake til innloggingsskjermen, har du oppdaget det klassiske problemet med tilstandspersistens. Denne oppførselen oppstår fordi vår nåværende implementering lagrer brukerdata i JavaScript-variabler som nullstilles ved hver sideoppdatering.

Problemer med nåværende implementering:

Den enkle account-variabelen fra vår forrige leksjon skaper tre betydelige problemer som påvirker både brukeropplevelse og kodevedlikehold:

Problem Teknisk årsak Brukerpåvirkning
Tap av økt Sideoppdatering nullstiller JavaScript-variabler Brukere må autentisere seg ofte
Spredte oppdateringer Flere funksjoner endrer tilstand direkte Feilsøking blir stadig vanskeligere
Ufullstendig opprydding Utlogging fjerner ikke alle tilstandsreferanser Potensielle sikkerhets- og personvernproblemer

Den arkitektoniske utfordringen:

Som Titanics oppdelte design som virket robust til flere rom ble oversvømt samtidig, vil det å fikse disse problemene individuelt ikke løse det underliggende arkitektoniske problemet. Vi trenger en omfattende løsning for tilstandshåndtering.

💡 Hva prøver vi egentlig å oppnå her?

Tilstandshåndtering handler egentlig om å løse to grunnleggende gåter:

  1. Hvor er dataene mine?: Holde oversikt over hvilken informasjon vi har og hvor den kommer fra
  2. Er alle på samme side?: Sørge for at det brukerne ser samsvarer med det som faktisk skjer

Vår handlingsplan:

I stedet for å jage vår egen hale, skal vi opprette et sentralisert system for tilstandshåndtering. Tenk på det som å ha én veldig organisert person som har kontroll på alt det viktige:

Skjema som viser dataflyten mellom HTML, brukerhandlinger og tilstand

Forstå denne dataflyten:

  • Sentraliserer all applikasjonstilstand på ett sted
  • Ruter alle tilstandsoppdateringer gjennom kontrollerte funksjoner
  • Sikrer at brukergrensesnittet forblir synkronisert med gjeldende tilstand
  • Gir et klart, forutsigbart mønster for databehandling

💡 Profesjonelt innblikk: Denne leksjonen fokuserer på grunnleggende konsepter. For komplekse applikasjoner gir biblioteker som Redux mer avanserte funksjoner for tilstandshåndtering. Å forstå disse grunnprinsippene vil hjelpe deg med å mestre ethvert bibliotek for tilstandshåndtering.

⚠️ Avansert emne: Vi dekker ikke automatiske UI-oppdateringer utløst av tilstandsforandringer, da dette involverer konsepter fra reaktiv programmering. Vurder dette som et utmerket neste steg i læringsreisen din!

Oppgave: Sentraliser tilstandsstruktur

La oss begynne å transformere vår spredte tilstandshåndtering til et sentralisert system. Dette første steget etablerer grunnlaget for alle forbedringene som følger.

Steg 1: Opprett et sentralt tilstandsobjekt

Erstatt den enkle account-deklarasjonen:

let account = null;

Med et strukturert tilstandsobjekt:

let state = {
  account: null
};

Hvorfor denne endringen er viktig:

  • Sentraliserer all applikasjonsdata på ett sted
  • Forbereder strukturen for å legge til flere tilstandsegenskaper senere
  • Skaper en klar grense mellom tilstand og andre variabler
  • Etablerer et mønster som skalerer etter hvert som appen din vokser

Steg 2: Oppdater tilgangsmønstre for tilstand

Oppdater funksjonene dine til å bruke den nye tilstandsstrukturen:

I register() og login()-funksjonene, erstatt:

account = ...

Med:

state.account = ...

I updateDashboard()-funksjonen, legg til denne linjen øverst:

const account = state.account;

Hva disse oppdateringene oppnår:

  • Opprettholder eksisterende funksjonalitet samtidig som strukturen forbedres
  • Forbereder koden din for mer sofistikert tilstandshåndtering
  • Skaper konsistente mønstre for tilgang til tilstandsdata
  • Etablerer grunnlaget for sentraliserte tilstandsoppdateringer

💡 Merk: Denne refaktoriseringen løser ikke umiddelbart problemene våre, men den skaper det essensielle grunnlaget for de kraftige forbedringene som kommer!

Implementering av kontrollerte tilstandsoppdateringer

Med vår tilstand sentralisert, innebærer neste steg å etablere kontrollerte mekanismer for datamodifikasjoner. Denne tilnærmingen sikrer forutsigbare tilstandsforandringer og enklere feilsøking.

Kjerneprinsippet ligner på flykontroll: i stedet for å tillate flere funksjoner å endre tilstand uavhengig, vil vi kanalisere alle endringer gjennom én kontrollert funksjon. Dette mønsteret gir klar oversikt over når og hvordan data endres.

Uforanderlig tilstandshåndtering:

Vi vil behandle vårt state-objekt som uforanderlig, noe som betyr at vi aldri endrer det direkte. I stedet skaper hver endring et nytt tilstandsobjekt med de oppdaterte dataene.

Selv om denne tilnærmingen kanskje virker ineffektiv sammenlignet med direkte modifikasjoner, gir den betydelige fordeler for feilsøking, testing og opprettholdelse av applikasjonens forutsigbarhet.

Fordeler med uforanderlig tilstandshåndtering:

Fordel Beskrivelse Påvirkning
Forutsigbarhet Endringer skjer kun gjennom kontrollerte funksjoner Enklere å feilsøke og teste
Historikksporing Hver tilstandsforandring skaper et nytt objekt Muliggjør angre/gjenta-funksjonalitet
Forebygging av bivirkninger Ingen utilsiktede modifikasjoner Forhindrer mystiske feil
Ytelsesoptimalisering Lett å oppdage når tilstanden faktisk endret seg Muliggjør effektive UI-oppdateringer

JavaScript-uforanderlighet med Object.freeze():

JavaScript tilbyr Object.freeze() for å forhindre objektmodifikasjoner:

const immutableState = Object.freeze({ account: userData });
// Any attempt to modify immutableState will throw an error

Hva som skjer her:

  • Forhindrer direkte egenskapsendringer eller slettinger
  • Kaster unntak hvis modifikasjonsforsøk gjøres
  • Sikrer at tilstandsforandringer må gå gjennom kontrollerte funksjoner
  • Skaper en klar kontrakt for hvordan tilstanden kan oppdateres

💡 Dypdykk: Lær om forskjellen mellom grunn og dyp uforanderlige objekter i MDN-dokumentasjonen. Å forstå denne distinksjonen er avgjørende for komplekse tilstandsstrukturer.

Oppgave

La oss opprette en ny updateState()-funksjon:

function updateState(property, newData) {
  state = Object.freeze({
    ...state,
    [property]: newData
  });
}

I denne funksjonen oppretter vi et nytt tilstandsobjekt og kopierer data fra den forrige tilstanden ved hjelp av spredningsoperatoren (...). Deretter overstyrer vi en bestemt egenskap i tilstandsobjektet med de nye dataene ved hjelp av brakettnotasjon [property] for tildeling. Til slutt låser vi objektet for å forhindre modifikasjoner ved hjelp av Object.freeze(). Vi har foreløpig bare account-egenskapen lagret i tilstanden, men med denne tilnærmingen kan du legge til så mange egenskaper du trenger i tilstanden.

Vi vil også oppdatere initialiseringen av state for å sikre at den opprinnelige tilstanden også er låst:

let state = Object.freeze({
  account: null
});

Deretter oppdaterer vi register-funksjonen ved å erstatte state.account = result;-tildelingen med:

updateState('account', result);

Gjør det samme med login-funksjonen, og erstatt state.account = data; med:

updateState('account', data);

Vi tar nå sjansen til å fikse problemet med at kontodata ikke blir fjernet når brukeren klikker på Logg ut.

Opprett en ny funksjon logout():

function logout() {
  updateState('account', null);
  navigate('/login');
}

I updateDashboard(), erstatt omdirigeringen return navigate('/login'); med return logout();

Prøv å registrere en ny konto, logge ut og inn igjen for å sjekke at alt fortsatt fungerer som det skal.

Tips: Du kan se på alle tilstandsforandringer ved å legge til console.log(state) nederst i updateState() og åpne konsollen i nettleserens utviklingsverktøy.

Implementering av datapersistens

Problemet med tap av økt som vi identifiserte tidligere krever en persistensløsning som opprettholder brukertilstanden på tvers av nettleserøkter. Dette forvandler applikasjonen vår fra en midlertidig opplevelse til et pålitelig, profesjonelt verktøy.

Tenk på hvordan atomklokker opprettholder presis tid selv gjennom strømbrudd ved å lagre kritisk tilstand i ikke-flyktig minne. På samme måte trenger webapplikasjoner vedvarende lagringsmekanismer for å bevare essensielle brukerdata på tvers av nettleserøkter og sideoppdateringer.

Strategiske spørsmål for datapersistens:

Før du implementerer persistens, vurder disse kritiske faktorene:

Spørsmål Kontekst for bankappen Beslutningspåvirkning
Er dataene sensitive? Kontosaldo, transaksjonshistorikk Velg sikre lagringsmetoder
Hvor lenge skal det vedvare? Innloggingsstatus vs. midlertidige UI-preferanser Velg passende lagringsvarighet
Trenger serveren det? Autentiseringstokens vs. UI-innstillinger Bestem delingskrav

Lagringsalternativer i nettleseren:

Moderne nettlesere tilbyr flere lagringsmekanismer, hver designet for forskjellige bruksområder:

Primære lagrings-API-er:

  1. localStorage: Vedvarende Key/Value-lagring

    • Vedvarer data på tvers av nettleserøkter på ubestemt tid
    • Overlever nettleseromstarter og datamaskinens omstart
    • Begrenset til det spesifikke nettstedets domene
    • Perfekt for brukerpreferanser og innloggingsstatus
  2. sessionStorage: Midlertidig øktlagring

    • Fungerer identisk med localStorage under aktive økter
    • Tømmes automatisk når nettleserfanen lukkes
    • Ideell for midlertidige data som ikke bør vedvare
  3. HTTP Cookies: Serverdelt lagring

    • Sendes automatisk med hver serverforespørsel
    • Perfekt for autentiseringstokens
    • Begrenset i størrelse og kan påvirke ytelsen

Krav til dataserialisering:

Både localStorage og sessionStorage lagrer kun strenger:

// 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'));

Forstå serialisering:

  • Konverterer JavaScript-objekter til JSON-strenger ved hjelp av JSON.stringify()
  • Rekonstruerer objekter fra JSON ved hjelp av JSON.parse()
  • Håndterer komplekse, nestede objekter og matriser automatisk
  • Feiler på funksjoner, udefinerte verdier og sirkulære referanser

💡 Avansert alternativ: For komplekse offline-applikasjoner med store datasett, vurder IndexedDB API. Det gir en fullverdig database på klientsiden, men krever en mer kompleks implementering.

Oppgave: Implementere localStorage-persistens

La oss implementere vedvarende lagring slik at brukerne forblir innlogget til de eksplisitt logger ut. Vi bruker localStorage for å lagre kontodata på tvers av nettleserøkter.

Trinn 1: Definer lagringskonfigurasjon

const storageKey = 'savedAccount';

Hva denne konstanten gir:

  • Oppretter en konsistent identifikator for våre lagrede data
  • Forhindrer skrivefeil i referanser til lagringsnøkler
  • Gjør det enkelt å endre lagringsnøkkelen hvis nødvendig
  • Følger beste praksis for vedlikeholdbar kode

Trinn 2: Legg til automatisk persistens

Legg til denne linjen på slutten av updateState()-funksjonen:

localStorage.setItem(storageKey, JSON.stringify(state.account));

Hva som skjer her:

  • Konverterer kontoobjektet til en JSON-streng for lagring
  • Lagrer dataene ved hjelp av vår konsistente lagringsnøkkel
  • Utfører automatisk hver gang tilstandsendringer oppstår
  • Sikrer at lagrede data alltid er synkronisert med gjeldende tilstand

💡 Arkitekturmessig fordel: Fordi vi sentraliserte alle tilstandsoppdateringer gjennom updateState(), krevde det bare én linje kode for å legge til persistens. Dette demonstrerer kraften i gode arkitektoniske beslutninger!

Trinn 3: Gjenopprett tilstand ved oppstart av appen

Opprett en initialiseringsfunksjon for å gjenopprette lagrede data:

function init() {
  const savedAccount = localStorage.getItem(storageKey);
  if (savedAccount) {
    updateState('account', JSON.parse(savedAccount));
  }

  // Our previous initialization code
  window.onpopstate = () => updateRoute();
  updateRoute();
}

init();

Forstå initialiseringsprosessen:

  • Henter eventuelle tidligere lagrede kontodata fra localStorage
  • Parser JSON-strengen tilbake til et JavaScript-objekt
  • Oppdaterer tilstanden ved hjelp av vår kontrollerte oppdateringsfunksjon
  • Gjenoppretter brukerens økt automatisk ved sideinnlasting
  • Utfører før ruteoppdateringer for å sikre at tilstanden er tilgjengelig

Trinn 4: Optimaliser standardruten

Oppdater standardruten for å dra nytte av persistens:

I updateRoute(), erstatt:

// Replace: return navigate('/login');
return navigate('/dashboard');

Hvorfor denne endringen gir mening:

  • Utnytter vårt nye persistenssystem effektivt
  • Lar dashbordet håndtere autentiseringssjekker
  • Omdirigerer automatisk til innlogging hvis ingen lagret økt eksisterer
  • Skaper en mer sømløs brukeropplevelse

Testing av implementeringen:

  1. Logg inn på din bankapp
  2. Oppdater nettlesersiden
  3. Bekreft at du forblir innlogget og på dashbordet
  4. Lukk og åpne nettleseren på nytt
  5. Naviger tilbake til appen og bekreft at du fortsatt er innlogget

🎉 Prestasjon oppnådd: Du har med suksess implementert vedvarende tilstandshåndtering! Appen din oppfører seg nå som en profesjonell webapplikasjon.

Balansering av persistens med dataintegritet

Vårt persistenssystem opprettholder brukerøkter, men introduserer en ny utfordring: datastagnasjon. Når flere brukere eller applikasjoner endrer de samme serverdataene, blir lokalbufret informasjon utdatert.

Denne situasjonen ligner på vikingnavigatører som stolte på både lagrede stjernekart og nåværende observasjoner av himmelen. Kartene ga konsistens, men navigatørene trengte ferske observasjoner for å ta hensyn til endrede forhold. På samme måte trenger vår applikasjon både vedvarende brukertilstand og oppdaterte serverdata.

🧪 Oppdage problemet med datastagnasjon:

  1. Logg inn på dashbordet med test-kontoen
  2. Kjør denne kommandoen i en terminal for å simulere en transaksjon fra en annen kilde:
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
  1. Oppdater dashbordet i nettleseren
  2. Observer om du ser den nye transaksjonen

Hva denne testen demonstrerer:

  • Viser hvordan localStorage kan bli "gammel" (utdatert)
  • Simulerer virkelige scenarier der dataendringer skjer utenfor appen din
  • Avslører spenningen mellom persistens og dataintegritet

Utfordringen med datastagnasjon:

Problem Årsak Brukeropplevelse
Utdaterte data localStorage utløper aldri automatisk Brukere ser utdatert informasjon
Serverendringer Andre apper/brukere endrer de samme dataene Ulike visninger på tvers av plattformer
Cache vs. virkelighet Lokal cache samsvarer ikke med servertilstand Dårlig brukeropplevelse og forvirring

Løsningsstrategi:

Vi implementerer et "oppdater ved innlasting"-mønster som balanserer fordelene med persistens med behovet for oppdaterte data. Denne tilnærmingen opprettholder en jevn brukeropplevelse samtidig som den sikrer datanøyaktighet.

Oppgave: Implementere system for dataoppdatering

Vi lager et system som automatisk henter oppdaterte data fra serveren samtidig som vi opprettholder fordelene med vår vedvarende tilstandshåndtering.

Trinn 1: Opprett oppdateringsfunksjon for kontodata

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);
}

Forstå logikken i denne funksjonen:

  • Sjekker om en bruker er innlogget (state.account eksisterer)
  • Omdirigerer til utlogging hvis ingen gyldig økt finnes
  • Henter oppdaterte kontodata fra serveren ved hjelp av den eksisterende getAccount()-funksjonen
  • Håndterer serverfeil på en smidig måte ved å logge ut ugyldige økter
  • Oppdaterer tilstanden med oppdaterte data ved hjelp av vårt kontrollerte oppdateringssystem
  • Trigger automatisk localStorage-persistens gjennom updateState()-funksjonen

Trinn 2: Opprett oppdateringshåndtering for dashbordet

async function refresh() {
  await updateAccountData();
  updateDashboard();
}

Hva denne oppdateringsfunksjonen oppnår:

  • Koordinerer dataoppdatering og UI-oppdateringsprosessen
  • Venter på at oppdaterte data skal lastes før visningen oppdateres
  • Sikrer at dashbordet viser den mest oppdaterte informasjonen
  • Opprettholder en ren separasjon mellom databehandling og UI-oppdateringer

Trinn 3: Integrer med rutesystemet

Oppdater rutekonfigurasjonen for å automatisk trigge oppdatering:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: refresh }
};

Hvordan denne integrasjonen fungerer:

  • Utfører oppdateringsfunksjonen hver gang dashbordruten lastes
  • Sikrer at oppdaterte data alltid vises når brukere navigerer til dashbordet
  • Opprettholder den eksisterende rutestrukturen samtidig som dataintegritet legges til
  • Gir et konsistent mønster for rutespesifikk initialisering

Testing av systemet for dataoppdatering:

  1. Logg inn på din bankapp
  2. Kjør curl-kommandoen fra tidligere for å opprette en ny transaksjon
  3. Oppdater dashbordet eller naviger bort og tilbake
  4. Bekreft at den nye transaksjonen vises umiddelbart

🎉 Perfekt balanse oppnådd: Appen din kombinerer nå den jevne opplevelsen av vedvarende tilstand med nøyaktigheten av oppdaterte serverdata!

GitHub Copilot Agent-utfordring 🚀

Bruk Agent-modus for å fullføre følgende utfordring:

Beskrivelse: Implementer et omfattende tilstandshåndteringssystem med angre/gjenta-funksjonalitet for bankappen. Denne utfordringen vil hjelpe deg med å øve på avanserte konsepter innen tilstandshåndtering, inkludert historikksporing, uforanderlige oppdateringer og synkronisering av brukergrensesnittet.

Oppgave: Lag et forbedret tilstandshåndteringssystem som inkluderer: 1) En historikk-array som sporer alle tidligere tilstander, 2) Angre- og gjenta-funksjoner som kan gå tilbake til tidligere tilstander, 3) UI-knapper for angre/gjenta-operasjoner på dashbordet, 4) En maksimal historikkgrense på 10 tilstander for å forhindre minneproblemer, og 5) Rydding av historikk når brukeren logger ut. Sørg for at angre/gjenta-funksjonaliteten fungerer med endringer i kontosaldo og vedvarer på tvers av nettleseroppdateringer.

Lær mer om agent mode her.

🚀 Utfordring: Optimalisering av lagring

Implementeringen din håndterer nå brukerøkter, dataoppdatering og tilstandshåndtering effektivt. Men vurder om vår nåværende tilnærming balanserer lagringseffektivitet med funksjonalitet optimalt.

Som sjakkmestere som skiller mellom essensielle brikker og utbyttbare bønder, krever effektiv tilstandshåndtering identifisering av hvilke data som må vedvare kontra hvilke som alltid bør hentes ferske fra serveren.

Analyse av optimalisering:

Evaluer din nåværende localStorage-implementering og vurder disse strategiske spørsmålene:

  • Hva er minimumsinformasjonen som kreves for å opprettholde brukerautentisering?
  • Hvilke data endres ofte nok til at lokalbufring gir liten fordel?
  • Hvordan kan lagringsoptimalisering forbedre ytelsen uten å forringe brukeropplevelsen?

Implementeringsstrategi:

  • Identifiser de essensielle dataene som må vedvare (sannsynligvis bare brukeridentifikasjon)
  • Endre din localStorage-implementering for kun å lagre kritiske sesjonsdata
  • Sørg for at oppdaterte data alltid lastes fra serveren ved dashbordbesøk
  • Test at din optimaliserte tilnærming opprettholder samme brukeropplevelse

Avansert vurdering:

  • Sammenlign avveiningene mellom å lagre fullstendige kontodata kontra kun autentiseringstoken
  • Dokumenter dine beslutninger og begrunnelser for fremtidige teammedlemmer

Denne utfordringen vil hjelpe deg å tenke som en profesjonell utvikler som vurderer både brukeropplevelse og applikasjonseffektivitet. Ta deg tid til å eksperimentere med forskjellige tilnærminger!

Quiz etter forelesning

Quiz etter forelesning

Oppgave

Implementer "Legg til transaksjon"-dialog

Her er et eksempelresultat etter å ha fullført oppgaven:

Skjermbilde som viser et eksempel på "Legg til transaksjon"-dialog


Ansvarsfraskrivelse:
Dette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten Co-op Translator. Selv om vi streber etter nøyaktighet, vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.