Når vi arbejder med Next.js og bygger webapplikationer, er der flere måder at strukturere vores projekter på. I dette kapitel udforsker vi et nyt paradigme for udvikling med React Server Components, som tilbyder en kraftfuld metode til at opbygge server-renderede applikationer. Denne tilgang fjerner behovet for isomorfisk JavaScript og gør det muligt at optimere både server- og klientkomponenter, hvilket er ideelt til store og komplekse projekter.
React Server Components gør det muligt at køre kode direkte på serveren, hvilket betyder, at kun statisk HTML sendes til klienten. Denne metode forbedrer både serverens ydeevne og browserens reaktionstid, da det reducerer behovet for at sende store mængder JavaScript til brugeren. I Next.js kan vi kategorisere komponenter i to hovedtyper: server-side og client-side. Server-side komponenter behandles på serveren og sendes som statisk HTML til klienten, hvilket reducerer belastningen på browseren. Client-side komponenter, på den anden side, kræver, at vi bruger direktivet "use client" i starten af filen, hvilket fortæller Next.js, at komponenten skal sendes som en del af JavaScript-bundlet til klienten.
For at implementere server-side komponenter i Next.js skal du oprette et nyt projekt, hvor du bruger en ny struktur baseret på App Router. I denne struktur er den primære mappe til projektet app, og rutenavne er baseret på mappenavnene. Inden for hver rute skal der være filer, der er navngivet i henhold til Next.js’ konventioner. De vigtigste filer i denne struktur er:
-
page.tsx: Denne fil bruges til at vise en side.
-
loading.tsx: Denne fil viser en "loading"-komponent, mens den egentlige side bliver indlæst.
-
layout.tsx: Tilsvarende filen
_app.tsxi det tidligere system, men her kan vi have flere layouts, der kan være indlejret i hinanden i næstede ruter. -
route.tsx: Denne fil bruges til at implementere en API-endpoint.
Lad os se på et konkret eksempel, der implementerer en simpel webapplikation med posts, hvor vi anvender den nye struktur.
Implementering af en simpel webapplikation med App Router
Vi starter med forsiden. For at gøre vores hjemmeside lidt mere interaktiv, kan vi tilføje en simpel tællerknap. Koden til en sådan knap kunne se sådan ud:
Denne komponent viser en knap, der øger tælleren, hver gang den bliver klikket. Ved at bruge use client direktivet gør vi Next.js opmærksom på, at denne komponent skal sendes til browseren som en del af JavaScript-bundlet. Vi kan derefter placere denne komponent på forsiden som følger:
Når vi arbejder med App Router, vil alle komponenter som standard blive behandlet som server-side komponenter, men da knappen er en client-side komponent, bliver den håndteret anderledes.
Omstrukturering af "About"-siden
Når vi går videre til "About"-siden, bliver koden betydeligt simplere. Ved at bruge den nye asynkrone komponentstruktur kan vi nemt hente data og præsentere det på serveren. Et eksempel kunne være en forespørgsel til GitHub API’et for at vise brugerens data:
Denne komponent gør en netværksanmodning og ventetiden på serveren håndteres korrekt. Ved at eksportere "force-dynamic"-variablen tvinger vi Next.js til at genopbygge siden for hver forespørgsel, hvilket betyder, at vi bruger server-side rendering (SSR) til dynamisk at hente og vise data.
Håndtering af dynamiske ruter
På "Posts"-siden ønsker vi at vise en liste af posts. Vi kan gøre dette på en meget ren og simpel måde. Først opretter vi en posts mappe med en page.tsx fil:
Denne komponent returnerer en liste af statiske post links. For at håndtere hver post, skal vi oprette en dynamisk rute ved at oprette en mappe med navnet [post] og tilføje en page.tsx fil der:
Denne kode bruger generateStaticParams til at definere, hvilke statiske sider der skal genereres under byggeprocessen. I stedet for at bruge getStaticPaths får vi nu en meget enklere og mere overskuelig måde at generere statiske sider på. Ved at eksportere revalidate variablen kan vi aktivere Incremental Static Regeneration (ISR), som opdaterer siden med den angivne frekvens (i dette tilfælde hver time).
Afsluttende betragtninger
Med denne tilgang til React Server Components og App Router har vi set, hvordan vi kan opbygge en mere effektiv og moderne applikation. Det giver ikke blot bedre ydeevne men også en simplere og mere fleksibel kodebase. Dog er det vigtigt at forstå, at denne metode stadig kun repræsenterer en del af Next.js’ muligheder. For at få et dybere kendskab til frameworket anbefales det at konsultere den officielle dokumentation, som giver omfattende information om de mange funktioner og konfigurationer, som Next.js tilbyder.
Hvordan man tester React-komponenter med Vitest og React Testing Library
Når vi taler om unit tests, refererer vi til test af små enheder, typisk funktioner, der udfører en logik og returnerer et resultat. Når det kommer til React-komponenter, ændrer konceptet sig ikke fundamentalt. React-komponenter er funktioner, der returnerer en DOM-struktur, og enheden vi tester, er altså en funktion, der genererer denne struktur. I unit testing af React-komponenter bruger vi ikke en rigtig browser, men i stedet en virtualiseret DOM kaldet JSDOM. Dette gør det muligt at teste komponenter uden at skulle renderere dem på en fysisk webside.
I denne kontekst kan React Testing Library være en afgørende hjælp. Denne bibliotek giver os de nødvendige værktøjer til at renderere komponenter, simulere events og derefter validere, om det ønskede resultat er opnået. Grundlæggende set hjælper det os med at simulere brugerinteraktioner, som et klik på en knap eller input i et tekstfelt, og giver os mulighed for at teste, om den rette opførsel sker som følge af disse handlinger.
Opsætning af testmiljøet
Før vi begynder at skrive tests, skal vi sikre, at vi har de nødvendige afhængigheder installeret. I et nyt Vite-projekt kan vi gøre dette med følgende kommando:
Disse pakker giver os mulighed for at bruge React Testing Library sammen med Vitest som testkører, og jsdom sørger for den virtualiserede DOM. Dernæst skal vi konfigurere miljøet til at arbejde med disse værktøjer. Dette gør vi ved at oprette en tests/setup.ts fil, som integrerer Vitest med React Testing Library.
I denne fil tilføjer vi:
Dette setup sikrer, at tests bliver renset korrekt efter hver testkørsel, hvilket forhindrer bivirkninger på tværs af testene.
For at integrere det i Vitest-konfigurationen, skal vi opdatere vite.config.ts:
Dette indikerer, at Vitest skal bruge jsdom og køre setup-filen, før testene starter.
Den første test: Rendering af en komponent
Nu, hvor miljøet er sat op, kan vi begynde at skrive tests for vores React-komponenter. En af de mest basale tests er at kontrollere, at en komponent er blevet korrekt renderet i dokumentet. Lad os tage et eksempel med en simpel App-komponent, der returnerer en overskrift:
For at teste denne komponent, kan vi skrive en test som følger:
I denne test bruger vi render fra React Testing Library til at renderere komponenten i en virtual DOM. Derefter bruger vi screen.getByText til at finde den specifikke tekst "Hello world" og validerer, at den findes i dokumentet ved hjælp af toBeInTheDocument.
Test af brugerinteraktion: Klik på en knap
Lad os nu se på et lidt mere komplekst eksempel, hvor vi tester interaktionen med en knap, der ændrer komponentens tilstand. Forestil dig, at vi har en komponent, der ændrer sin className, når knappen bliver klikket:
For at teste denne funktionalitet, kan vi skrive en test, der simulerer et klik på knappen og tjekker, om className bliver opdateret korrekt:
I dette eksempel bruger vi fireEvent.click til at simulere et klik på knappen og toHaveClass for at validere, om elementet nu har klassen "active".
Mocking af eksterne API-anmodninger
I mange applikationer vil vi interagere med eksterne data via API-anmodninger. I unit testing er det vigtigt at mocke disse anmodninger for at isolere testen fra eksterne afhængigheder. En måde at gøre dette på er ved at bruge Mock Service Worker (MSW), som gør det muligt at mocke serveranmodninger på en fleksibel måde.
Her er et eksempel på, hvordan man kan mocke en GET-anmodning til GitHub API'et:
Her opretter vi en mock server, der responderer på GET-anmodninger til en given URL med et specifikt JSON-svar. Vi bruger beforeAll, afterEach, og afterAll til at sikre, at serveren håndterer anmodningerne korrekt under hele testens livscyklus.
Vigtige overvejelser for læseren
Når man skriver enhedstests for React-komponenter, er det vigtigt at have en forståelse af, at tests ikke kun er en måde at sikre korrekt funktionalitet på, men også en metode til at opdage utilsigtede fejl og give større sikkerhed i projektet. En god testdækning, der omfatter både positive og negative scenarier, kan hjælpe med at minimere fejl, når applikationen vokser og udvikler sig. Det er også vigtigt at forstå, at man ikke bør teste implementeringen af komponenterne for meget, men snarere deres offentlige API og hvordan de interagerer med brugeren.
Hvordan brugere reagerer på berøringer i React Native-applikationer
Når vi arbejder med brugerinteraktioner i React Native, er det afgørende at give brugeren visuelt feedback, når de interagerer med elementer på skærmen. Især når der bruges berøringsgestikter som at trykke på knapper eller swipe på elementer. I denne sammenhæng spiller komponenterne, der håndterer berøringer, en central rolle for at sikre, at interaktionen er både intuitiv og behagelig.
En af de grundlæggende komponenter i React Native til at håndtere scrollbare områder er ScrollView. Denne komponent i sig selv er ikke særlig funktionel, medmindre den bruges til at pakke andre komponenter ind, som skal rulles. For at ScrollView kan fungere korrekt, er det nødvendigt at angive en højde. En simpel stil kunne se sådan ud:
Her sætter vi højden til 1, mens alignSelf med værdien "stretch" sikrer, at indholdet bliver vist korrekt. Det resulterer i en vertikal scrollbar, som brugeren kan trække ned for at navigere gennem indholdet. Ved at lege med denne funktion kan brugeren eksperimentere med forskellige bevægelser og få følelsen af, hvordan man kan få indholdet til at scrolle automatisk eller stoppe det.
En anden vigtig del af brugerinteraktion er at give visuel feedback, når brugeren rører ved et element. For eksempel kan tekst, der fungerer som en knap eller et link, have visuel feedback, så brugeren ved, at det er muligt at trykke på det. Selvom React Native ikke har en direkte komponent som en web-linkkomponent, kan vi opnå denne funktionalitet ved at style teksten, så den ser ud som en trykbar knap.
Problemet ved at style tekst som en knap på mobile enheder er dog, at det kan være svært for brugerne at ramme den rette størrelse. Knapper giver en større overflade og dermed en lettere målretning for fingerbevægelser. For at give ekstra visuel feedback, når en bruger trykker på en knap, kan vi anvende komponenter som TouchableOpacity, TouchableHighlight og Pressable.
Når brugeren interagerer med en TouchableOpacity komponent, reduceres opaciteten af knappen, hvilket giver en tydelig visuel feedback. Dette betyder, at knappen ser ud som om den bliver "trykket ned". For eksempel:
I tilfælde af TouchableHighlight ændres ikke opaciteten, men et lag af farve på knappen tilføjes, når den trykkes. Her kan du bruge en gennemsigtig version af den farve, der allerede anvendes på knappen:
Der er også den mere fleksible Pressable komponent, som gør det muligt at registrere flere tryk-tilstande, såsom onPressIn, onPressOut og onLongPress. Med Pressable kan vi implementere knapfeedback, som ændrer sig, alt efter hvilken type interaktion brugeren har. For eksempel:
Dette giver en endnu mere nuanceret brugeroplevelse, da der er mulighed for at give feedback på flere niveauer.
Det er dog ikke kun knapper, der kræver opmærksomhed på berøringsfeedback. Et andet almindeligt element i mobilapps er muligheden for at swipe på skærmen. Dette gøres ofte ved hjælp af en komponent som Swipeable. Dette tillader brugeren at swipe et element væk, som kan udløse en callback, der fjerner elementet fra visningen.
Når brugeren swiper et element væk, fjernes det fra visningen, hvilket gør det muligt at implementere funktioner som at slette eller arkivere elementer hurtigt.
Det er vigtigt at forstå, at berøringsfeedback ikke kun handler om at implementere visuelt feedback, men også om at gøre brugerinteraktionen så naturlig som muligt. Gestusbaserede interaktioner som scrolling, swipe og tryk skal være intuitivt forståelige for brugerne. Hvis en funktion ikke er opdagelig, risikerer vi at forvirre brugerne og skabe en mindre brugervenlig app.
Endvidere er det essentielt at vælge de rigtige komponenter og metoder til den type interaktion, der er mest passende for appens formål og den enhed, der anvendes. For eksempel kan en Pressable-knap være ideel til interaktioner, der kræver flere faser af feedback, mens en TouchableOpacity-komponent kan være tilstrækkelig til en simpel trykbar knap. At anvende disse komponenter effektivt er nøglen til at skabe en flydende og brugervenlig oplevelse i mobilapplikationer.
Hvordan viser man fremdrift i en app ved hjælp af progress barer og loading indikatorer?
At vise fremdrift i en applikation kan være en uundværlig funktion, især når man håndterer operationer, der tager tid. Det kan være alt fra dataindlæsning, serverkommunikation til filoverførsler. Brugeren skal informeres om, at noget foregår i baggrunden, og for at undgå følelsen af usikkerhed og frustration, er det ofte en god idé at vise præcis, hvor meget der er tilbage, eller hvor lang tid der er gået. En simpel "loading spinner" er én måde at vise, at noget foregår, men det er sjældent nok til at skabe en god brugeroplevelse. Denne artikel ser på, hvordan man kan implementere en avanceret loading indikator og progress bar, der giver brugeren en mere tilfredsstillende oplevelse, især når man arbejder med navigation og flere skærme i en app.
En grundlæggende metode til at håndtere loading tilstande i React Native er ved hjælp af en wrapper komponent, der håndterer visningen af et indhold baseret på en "loading" tilstand. For eksempel kan vi skabe en LoadingWrapper komponent, som venter et sekund, før den viser det oprindelige indhold.
Denne komponent bruger en useEffect hook til at vente i et sekund, før den ændrer loading tilstanden og viser det oprindelige indhold, som er gemt i children. Dette er en god løsning til at skjule ekstra logik og gøre det nemmere at genbruge denne wrapper på tværs af forskellige skærme i applikationen. I en reel applikation kan du for eksempel give LoadingWrapper yderligere props for at få fuld kontrol over loading-tilstanden fra den skærm, der bruger wrapperen.
Men blot at indikere, at noget foregår i baggrunden er ofte ikke tilstrækkeligt. Brugeren kan føle en vis ængstelse, når der ikke er noget klart mål for, hvornår processen er afsluttet. Et godt eksempel er, når man venter på, at noget skal tilberedes i en mikrobølgeovn, men uden en timer – man har ingen idé om, hvornår det bliver færdigt. Dette skaber en følelse af usikkerhed, som kan undgås ved at vise præcis, hvor meget der er opnået, og hvor langt der er tilbage. Derfor er det generelt en god idé at bruge en progress bar, der kan vise brugeren den faktiske fremdrift.
I React Native er der dog ikke en platform-agnostisk komponent til progress barer, som der er for ActivityIndicator. For at vise progress barer i applikationer kan vi i stedet bruge biblioteket react-native-progress, som giver fleksible og lette løsninger til at implementere progress barer.
For at bygge en simpel ProgressBar komponent, der accepterer en fremdriftsværdi og viser både en progress bar og en procentværdi, kan vi skrive følgende kode:
Denne komponent renderer en progress bar sammen med den procentvise fremdrift, og den anvender den nødvendige prop for at tilpasse fremdriften.
I en typisk applikation kan du bruge ProgressBar komponenten til at vise en progression, der simulerer noget som f.eks. en filupload. Ved at bruge useState og useEffect hooks kan vi opdatere fremdriften løbende og give brugeren en idé om, hvornår processen afsluttes:
Denne kode simulerer en timer, der gradvist opdaterer fremdriften, og viser en progress bar, som indikerer, at en proces er i gang. Selvom denne simulering af en timer sjældent vil blive brugt i en produktion, kan den være nyttig i specifikke tilfælde som statistiske dataindlæsninger eller opdatering af status for uploads til servere.
En mere avanceret metode til at vise fremdrift er at bruge en step progress bar, som indikerer, hvor langt brugeren er i en forhåndsdefineret sekvens. For eksempel kan du opdele en formular i flere logiske sektioner og vise en progress bar, der opdateres, hver gang en bruger afslutter én sektion og går videre til næste. Denne tilgang kan være særlig nyttig i apps, hvor brugeren skal igennem flere trin, som f.eks. i onboarding-processer.
I et konkret eksempel, hvor appen består af flere skærme, kan man bruge react-navigation til at vise en progress bar, der reflekterer brugerens progression gennem skærmene. Her vises progressen i navigationsbaren under titlen, og den opdateres, hver gang brugeren navigerer til en ny skærm. I denne opsætning kan vi bruge ProgressBar komponenten til at opdatere progressen dynamisk baseret på den aktuelle position i navigationsstakken.
I React Native kan det være en fordel at bruge en centraliseret struktur til at beregne fremdriften, som f.eks. at opbevare ruterne i en konstant og derefter bruge den til at beregne procentdelen baseret på den aktuelle skærms position i rutearrayet. Denne metode giver en elegant måde at vise, hvor langt brugeren er kommet, og hvad der er tilbage.
For at opsummere: At vise fremdrift i en applikation er ikke kun en måde at informere brugeren på, men en vigtig del af at skabe en god brugeroplevelse. Ved at bruge både loading indikatorer og progress barer kan du give brugeren både visuel og psykologisk feedback om, hvad der sker i baggrunden. Det er også en god idé at gøre fremdriften så præcis som muligt, især når brugeren navigerer gennem flere skærme eller sektioner, så de altid ved, hvor langt de er kommet, og hvad der er tilbage.
Hvordan skaber man smagfulde og nærende no-cook bowls med friske ingredienser?
Hvordan forskellige urter beriger haven og vores sanser
Hvem forsøger at skade Young Wild West, og hvorfor?
Hvordan kroppen reagerer på bevidsthed og afslapning gennem somatiske øvelser
Hvordan C.V. Raman opdagede, hvorfor havet er blåt
Hvordan kan tarsaltunnelsyndrom diagnosticeres og behandles?
Hvordan du undgår skader på din hund under leg med aktivitetsbolde og læring af nye tricks
Hvordan håndterer man håbet og usikkerheden under krigstid?
Hvordan madtraditioner afspejler kulturer og deres udvikling gennem tid

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский