Skapa meningsfulla loading.tsx-filer och skelett
Bygg laddningstillstånd på routenivå och skelettplatshållare som matchar den slutliga layouten för att undvika layoutförskjutningar.
Skapa meningsfulla loading.tsx-filer och skelett är en gratis lektion i Next.js 15 fullstack (App Router + Server Actions) på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Next.js 15 fullstack (App Router + Server Actions), och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Next.js 15 fullstack (App Router + Server Actions) innehåller totalt 4 lektioner.
Varför loading.tsx finns
I App Router är en fil med namnet loading.tsx speciell: Next.js omsluter automatiskt route-segmentets page.tsx med en React-<Suspense>-gräns och visar loading.tsx som reservinnehåll medan serverkomponenten strömmas.
- Ni får ett omedelbart laddningstillstånd med noll manuell Suspense-konfiguration.
- Det aktiveras endast vid rendering på servern av segmentet, inte vid varje interaktion på klienten.
- Reservinnehållet visas direkt medan sidans asynkrona data blir klar.
Den här lektionen handlar om att göra reservinnehållet meningsfullt, så att användaren upplever sidan som snabb och layouten inte hoppar.
Filkonventionen
Lägg en loading.tsx bredvid page.tsx i valfritt route-segment. Dess standardexport renderas som Suspense-reservinnehåll för segmentet och allt under det.
- Det är en vanlig React-komponent — den kan vara en Server Component (standard), eftersom den endast renderar statisk markup.
- Inga props skickas till den; den måste vara fristående.
- Håll den lättviktig så att den skickas och renderas snabbt.
// app/dashboard/loading.tsx
export default function Loading() {
return (
<div className="dashboard-grid" aria-busy="true">
<DashboardSkeleton />
</div>
);
}Det verkliga målet: undvik layoutförskjutningar
Ett dåligt laddningstillstånd ersätter sidan med en centrerad laddningsindikator och hoppar sedan till en helt annan layout när datan kommer. Det visuella hoppet försämrar den upplevda prestandan och Cumulative Layout Shift (CLS).
Ett bra skelett speglar den slutliga layouten:
- Samma antal kort, rader och kolumner.
- Ungefär samma bredd och höjd som det riktiga innehållet.
- Samma avstånd och rutnätsstruktur.
När den riktiga datan ersätter platshållarna flyttar sig ingenting — endast de grå platshållarna fylls med innehåll.
En återanvändbar skelett-primitive
Börja med en enda liten byggsten: en Skeleton-ruta som renderar en grå, rundad rektangel. Allt annat bygger Ni genom att komponera med den.
- Acceptera
classNameså att anropande kod kan styra bredd, höjd och form. - Lägg till stilen
animate-pulse(Tailwind) eller en CSS-shimmer-effekt för att skapa en laddningskänsla. - Märk den med
aria-hidden— den är dekorativ och inte faktiskt innehåll.
// components/skeleton.tsx
export function Skeleton({ className = '' }: { className?: string }) {
return (
<div
aria-hidden="true"
className={`animate-pulse rounded-md bg-gray-200 ${className}`}
/>
);
}Matcha den slutliga layouten
Bygg skeletonet genom att kopiera strukturen från den riktiga komponenten och sedan ersätta text och bilder med Skeleton-rutor i motsvarande storlek.
- En avatar blir en cirkel:
h-10 w-10 rounded-full. - En rubrikrad blir ett brett fält och en underrubrik blir ett kortare, tunnare fält.
- Använd samma containerklasser (utfyllnad, mellanrum och kantlinje) som i det riktiga kortet.
// components/user-card-skeleton.tsx
import { Skeleton } from './skeleton';
export function UserCardSkeleton() {
return (
<div className="flex items-center gap-4 rounded-lg border p-4">
<Skeleton className="h-10 w-10 rounded-full" />
<div className="flex-1 space-y-2">
<Skeleton className="h-4 w-1/3" />
<Skeleton className="h-3 w-1/2" />
</div>
</div>
);
}Listor: upprepa radskeletonet
För listor och tabeller renderar Ni ett fast antal radskeleton — tillräckligt många för att fylla den typiska visningsytan så att sidan ser komplett ut.
- Återanvänd skeletonet för en enskild rad i en array.
- Välj ett antal som ungefär motsvarar den vanliga sidstorleken (t.ex. 6–8 rader).
- Behåll samma
gapoch omslutande element som i den riktiga listan för att bevara avstånden.
// components/user-list-skeleton.tsx
import { UserCardSkeleton } from './user-card-skeleton';
export function UserListSkeleton({ rows = 6 }: { rows?: number }) {
return (
<div className="space-y-3">
{Array.from({ length: rows }).map((_, i) => (
<UserCardSkeleton key={i} />
))}
</div>
);
}Koppla in skeletonet i loading.tsx
Nu komponerar loading.tsx bara Era skeleton-komponenter i samma yttre layout som sidan. Sidhuvudet, som är statiskt (inte databeroende), kan renderas på riktigt även i laddningstillståndet.
- Rendera de riktiga delarna som visas direkt (sidrubrik och flikar).
- Byt bara ut de databundna områdena mot skeleton.
- Det gör att sidan redan känns delvis laddad.
// app/dashboard/users/loading.tsx
import { UserListSkeleton } from '@/components/user-list-skeleton';
export default function Loading() {
return (
<section className="mx-auto max-w-2xl p-6">
<h1 className="mb-4 text-2xl font-bold">Users</h1>
<UserListSkeleton rows={6} />
</section>
);
}loading.tsx jämfört med Suspense på komponentnivå
loading.tsx täcker hela segmentet — om någon data på sidan är långsam visas hela reservvyn. Ibland behöver Ni mer detaljerad kontroll så att snabbt innehåll renderas först.
- Använd
loading.tsxför den första renderingen som gäller hela segmentet. - Omslut enskilda långsamma komponenter med
<Suspense>och en egen skeleton-reservvy så att de kan strömmas oberoende av varandra. - Kombinera båda: ett enkelt segmentskeleton plus detaljerad Suspense för den långsammaste widgeten.
// app/dashboard/page.tsx
import { Suspense } from 'react';
import { RevenueChart } from './revenue-chart';
import { ChartSkeleton } from './chart-skeleton';
export default function Page() {
return (
<main className="p-6">
<h1 className="text-2xl font-bold">Overview</h1>
{/* Static + fast content paints immediately */}
<Suspense fallback={<ChartSkeleton />}>
{/* Slow async server component streams in later */}
<RevenueChart />
</Suspense>
</main>
);
}Ren funktion för antal skeleton
Hur många skeletonrader bör Ni visa? En liten hjälpfunktion håller antalet konsekvent och begränsar det till ett rimligt intervall, så att Ni aldrig renderar ett orimligt antal platshållare.
Det här är vanlig TypeScript-logik — inget ramverk är inblandat — så den kan enhetstestas separat.
function skeletonRowCount(pageSize: number, viewportRows = 8): number {
if (!Number.isFinite(pageSize) || pageSize <= 0) return viewportRows;
return Math.min(pageSize, viewportRows);
}
console.log(skeletonRowCount(20)); // 8 (clamped to viewport)
console.log(skeletonRowCount(3)); // 3 (fewer items than viewport)
console.log(skeletonRowCount(0)); // 8 (fallback default)
console.log(skeletonRowCount(-5)); // 8 (guards invalid input)Tillgänglighet och reducerad rörelse
Skeleton är dekorativa, men de påverkar ändå hjälpmedel och användare som är känsliga för rörelser.
- Märk laddningsområdet med
aria-busy="true"och enskilda platshållare medaria-hidden="true". - Tillhandahåll en visuellt dold status, till exempel
<span className="sr-only">Loading users</span>, för skärmläsare. - Respektera
prefers-reduced-motionså att pulsanimeringen inte körs för användare som har valt bort den.
/* globals.css */
@media (prefers-reduced-motion: reduce) {
.animate-pulse {
animation: none;
}
}Vanliga fallgropar
Undvik följande misstag, som motverkar syftet med ett skeleton:
- Reservvy med endast en spinner: ger ingen ledtråd om layouten och leder garanterat till ett skifte när innehållet anländer.
- Felaktiga storlekar: om skeletonkortet är 60px högt men det riktiga kortet är 96px hoppar sidan fortfarande.
- Glömd omslutning: olika utfyllnad eller rutnät mellan skeletonet och sidan flyttar allt.
- Skeleton för snabb data: om ett segment laddas på <100ms kan skeletonet blinka till och kännas sämre — överväg Suspense på komponentnivå enbart för de långsamma delarna.
Snabbtest
Testa Era kunskaper om laddningstillstånd och skeleton på routenivå.
Sammanfattning
Ni har lärt Er att utforma meningsfulla laddningstillstånd i App Router:
loading.tsxär en automatisk Suspense-reservvy för sitt routsegment.- Bygg skeleton från en liten
Skeleton-primitiv och komponera dem så att de speglar den slutliga layouten. - Matcha omslutningar, antal och dimensioner för att undvika layoutskifte (CLS).
- Rendera statiska delar som visas direkt (rubriker och flikar) på riktigt; använd skeleton enbart för de databundna områdena.
- Använd
loading.tsxför den första renderingen av hela segmentet och<Suspense>på komponentnivå för att strömma långsamma widgetar oberoende av varandra. - Hantera tillgänglighet med
aria-busy,aria-hidden, ensr-only-status ochprefers-reduced-motion.
Lär dig TypeScript med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”Skapa meningsfulla loading.tsx-filer och skelett” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Next.js 15 fullstack (App Router + Server Actions), inklusive ”Skapa meningsfulla loading.tsx-filer och skelett”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Next.js 15 fullstack (App Router + Server Actions) innehåller totalt 4 lektioner.
Vad lär jag mig i ”Skapa meningsfulla loading.tsx-filer och skelett”?
Bygg laddningstillstånd på routenivå och skelettplatshållare som matchar den slutliga layouten för att undvika layoutförskjutningar. Ni övar på Next.js 15 fullstack (App Router + Server Actions) med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Next.js 15 fullstack (App Router + Server Actions)?
Du behöver inga förkunskaper. Utbildningen i Next.js 15 fullstack (App Router + Server Actions) på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Skapa meningsfulla loading.tsx-filer och skelett”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Next.js 15 fullstack (App Router + Server Actions)-lektionen?
Ja. Varje Next.js 15 fullstack (App Router + Server Actions)-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Suspense-gränser och strömning på komponentnivå
- Skapa meningsfulla loading.tsx-filer och skelett
- Partiell förhandsrendering: statiskt skal, dynamiska luckor
- Fallgropar vid strömning: layoutförskjutning och vattenfall