Utforsk essensielle navigeringsmønstre med React Router v6. Lær deklarativ ruting, dynamiske ruter, programmatisk navigering, nestede ruter og datainnlastingsstrategier for å bygge robuste og brukervennlige webapplikasjoner.
React Router v6: Mestre navigeringsmønstre for moderne webapplikasjoner
React Router v6 er et kraftig og fleksibelt rutingsbibliotek for React-applikasjoner. Det lar deg lage enkeltsideapplikasjoner (SPA-er) med en sømløs brukeropplevelse ved å håndtere navigasjon uten fullstendig sideinnlasting. Dette blogginnlegget vil dykke ned i essensielle navigeringsmønstre ved hjelp av React Router v6, og gi deg kunnskapen og eksemplene for å bygge robuste og brukervennlige webapplikasjoner.
Forstå kjernekonseptene i React Router v6
Før vi dykker ned i spesifikke mønstre, la oss gå gjennom noen grunnleggende konsepter:
- Deklarativ ruting: React Router bruker en deklarativ tilnærming, der du definerer rutene dine som React-komponenter. Dette gjør rutingslogikken din tydelig og vedlikeholdbar.
- Komponenter: Kjernekomponentene inkluderer
BrowserRouter
,HashRouter
,MemoryRouter
,Routes
ogRoute
. - Hooks: React Router tilbyr hooks som
useNavigate
,useLocation
,useParams
oguseRoutes
for å få tilgang til rutingsinformasjon og manipulere navigasjon.
1. Deklarativ ruting med <Routes>
og <Route>
Grunnlaget for React Router v6 ligger i deklarativ ruting. Du definerer rutene dine ved hjelp av <Routes>
- og <Route>
-komponentene. <Routes>
-komponenten fungerer som en container for rutene dine, og <Route>
-komponenten definerer en spesifikk rute og komponenten som skal rendres når den ruten samsvarer med den nåværende URL-en.
Eksempel: Grunnleggende rutekonfigurasjon
Her er et grunnleggende eksempel på hvordan du setter opp ruter for en enkel applikasjon:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Contact from "./pages/Contact";
function App() {
return (
} />
} />
} />
);
}
export default App;
I dette eksempelet definerer vi tre ruter:
/
: RendrerHome
-komponenten./about
: RendrerAbout
-komponenten./contact
: RendrerContact
-komponenten.
BrowserRouter
-komponenten muliggjør ruting basert på nettleserhistorikk. React Router sammenligner den nåværende URL-en med de definerte rutene og rendrer den tilsvarende komponenten.
2. Dynamiske ruter med URL-parametere
Dynamiske ruter lar deg lage ruter som kan håndtere forskjellige verdier i URL-en. Dette er nyttig for å vise innhold basert på en unik identifikator, for eksempel en produkt-ID eller en bruker-ID. React Router v6 bruker :
-symbolet for å definere URL-parametere.
Eksempel: Vise produktdetaljer
La oss si du har en e-handelsapplikasjon og ønsker å vise detaljer for hvert produkt basert på ID-en. Du kan definere en dynamisk rute som dette:
import { BrowserRouter, Routes, Route, useParams } from "react-router-dom";
function ProductDetails() {
const { productId } = useParams();
// Hent produktdetaljer basert på productId
// ...
return (
Produktdetaljer
Produkt-ID: {productId}
{/* Vis produktdetaljer her */}
);
}
function App() {
return (
} />
);
}
export default App;
I dette eksempelet:
/products/:productId
definerer en dynamisk rute der:productId
er en URL-parameter.useParams
-hooken brukes til å få tilgang til verdien avproductId
-parameteren inne iProductDetails
-komponenten.- Du kan deretter bruke
productId
til å hente de tilsvarende produktdetaljene fra datakilden din.
Eksempel på internasjonalisering: Håndtering av språkkoder
For en flerspråklig nettside kan du bruke en dynamisk rute for å håndtere språkkoder:
} />
Denne ruten vil matche URL-er som /en/about
, /fr/about
og /es/about
. lang
-parameteren kan deretter brukes til å laste inn de riktige språkressursene.
3. Programmatisk navigering med useNavigate
Selv om deklarativ ruting er flott for statiske lenker, må du ofte navigere programmatisk basert på brukerhandlinger eller applikasjonslogikk. React Router v6 tilbyr useNavigate
-hooken for dette formålet. useNavigate
returnerer en funksjon som lar deg navigere til forskjellige ruter.
Eksempel: Omdirigere etter skjemainnsending
La oss si du har en skjemainnsending og ønsker å omdirigere brukeren til en suksess-side etter at skjemaet er sendt inn:
import { useNavigate } from "react-router-dom";
function MyForm() {
const navigate = useNavigate();
const handleSubmit = async (event) => {
event.preventDefault();
// Send skjemadata
// ...
// Omdiriger til suksess-siden etter vellykket innsending
navigate("/success");
};
return (
);
}
export default MyForm;
I dette eksempelet:
- Vi bruker
useNavigate
-hooken for å fånavigate
-funksjonen. - Etter at skjemaet er sendt inn, kaller vi
navigate("/success")
for å omdirigere brukeren til/success
-ruten.
Sende med 'state' under navigering
Du kan også sende med 'state' sammen med navigeringen ved å bruke det andre argumentet til navigate
:
navigate("/confirmation", { state: { orderId: "12345" } });
Dette lar deg sende data til målkomponenten, som kan nås ved hjelp av useLocation
-hooken.
4. Nestede ruter og layouter
Nestede ruter lar deg lage hierarkiske rutingsstrukturer, der en rute er nestet inne i en annen. Dette er nyttig for å organisere komplekse applikasjoner med flere nivåer av navigasjon. Dette hjelper med å lage layouter der visse UI-elementer er konsekvent til stede på tvers av en del av applikasjonen.
Eksempel: Brukerprofilseksjon
La oss si at du har en brukerprofilseksjon med nestede ruter for å vise brukerens profilinformasjon, innstillinger og ordrer:
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function Profile() {
return (
Brukerprofil
-
Profilinformasjon
-
Innstillinger
-
Ordrer
} />
} />
} />
);
}
function ProfileInformation() {
return Profilinformasjon-komponent
;
}
function Settings() {
return Innstillinger-komponent
;
}
function Orders() {
return Ordrer-komponent
;
}
function App() {
return (
} />
);
}
export default App;
I dette eksempelet:
/profile/*
-ruten matcher enhver URL som starter med/profile
.Profile
-komponenten rendrer en navigeringsmeny og en<Routes>
-komponent for å håndtere de nestede rutene.- De nestede rutene definerer komponentene som skal rendres for
/profile/info
,/profile/settings
og/profile/orders
.
*
i den overordnede ruten er avgjørende; den signaliserer at den overordnede ruten skal matche enhver underbane, slik at de nestede rutene kan matches riktig inne i Profile
-komponenten.
5. Håndtere «Ikke funnet» (404)-feil
Det er viktig å håndtere tilfeller der brukeren navigerer til en rute som ikke eksisterer. React Router v6 gjør dette enkelt med en «catch-all»-rute.
Eksempel: Implementere en 404-side
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function NotFound() {
return (
404 - Ikke funnet
Siden du leter etter, finnes ikke.
Gå tilbake til forsiden
);
}
function App() {
return (
} />
} />
} />
);
}
I dette eksempelet:
<Route path="*" element={<NotFound />} />
-ruten er en «catch-all»-rute som matcher enhver URL som ikke matcher noen av de andre definerte rutene.- Det er viktig å plassere denne ruten på slutten av
<Routes>
-komponenten slik at den bare matcher hvis ingen annen rute matcher.
6. Strategier for datainnlasting med React Router v6
React Router v6 inkluderer ikke innebygde datainnlastingsmekanismer som sin forgjenger (React Router v5 med `useRouteMatch`). Imidlertid gir den verktøyene til å implementere ulike datainnlastingsstrategier effektivt.
Alternativ 1: Hente data i komponenter
Den enkleste tilnærmingen er å hente data direkte i komponenten som rendrer ruten. Du kan bruke useEffect
-hooken for å hente data når komponenten monteres eller når URL-parametrene endres.
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
function ProductDetails() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchProduct() {
try {
const response = await fetch(`/api/products/${productId}`);
if (!response.ok) {
throw new Error(`HTTP-feil! Status: ${response.status}`);
}
const data = await response.json();
setProduct(data);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchProduct();
}, [productId]);
if (loading) return Laster...
;
if (error) return Feil: {error.message}
;
if (!product) return Produkt ikke funnet
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
Denne tilnærmingen er enkel, men kan føre til duplisering av kode hvis du trenger å hente data i flere komponenter. Det er også mindre effektivt fordi datainnhentingen starter først etter at komponenten er montert.
Alternativ 2: Bruke en egendefinert hook for datainnhenting
For å redusere kodeduplisering kan du lage en egendefinert hook som innkapsler logikken for datainnhenting. Denne hooken kan deretter gjenbrukes i flere komponenter.
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP-feil! Status: ${response.status}`);
}
const json = await response.json();
setData(json);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
}
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetch;
Deretter kan du bruke denne hooken i komponentene dine:
import { useParams } from "react-router-dom";
import useFetch from "./useFetch";
function ProductDetails() {
const { productId } = useParams();
const { data: product, loading, error } = useFetch(`/api/products/${productId}`);
if (loading) return Laster...
;
if (error) return Feil: {error.message}
;
if (!product) return Produkt ikke funnet
;
return (
{product.name}
{product.description}
);
}
export default ProductDetails;
Alternativ 3: Bruke et rutingsbibliotek med datainnhentingsfunksjoner (TanStack Router, Remix)
Biblioteker som TanStack Router og Remix tilbyr innebygde datainnhentingsmekanismer som integreres sømløst med ruting. Disse bibliotekene tilbyr ofte funksjoner som:
- Loaders: Funksjoner som kjøres *før* en rute blir rendret, slik at du kan hente data og sende dem til komponenten.
- Actions: Funksjoner som håndterer skjemainnsendinger og datamutasjoner.
Å bruke et slikt bibliotek kan drastisk forenkle datainnlasting og forbedre ytelsen, spesielt for komplekse applikasjoner.
Serverside-rendring (SSR) og statisk sidegenerering (SSG)
For forbedret SEO og ytelse ved første innlasting, bør du vurdere å bruke SSR eller SSG med rammeverk som Next.js eller Gatsby. Disse rammeverkene lar deg hente data på serveren eller under byggeprosessen og servere forhåndsrendret HTML til klienten. Dette eliminerer behovet for at klienten må hente data ved første innlasting, noe som resulterer i en raskere og mer SEO-vennlig opplevelse.
7. Jobbe med forskjellige rutertyper
React Router v6 tilbyr forskjellige ruterimplementeringer for å passe til ulike miljøer og bruksområder:
- BrowserRouter: Bruker HTML5 history API (
pushState
,replaceState
) for navigasjon. Det er det vanligste valget for webapplikasjoner som kjører i et nettlesermiljø. - HashRouter: Bruker hash-delen av URL-en (
#
) for navigasjon. Dette er nyttig for applikasjoner som trenger å støtte eldre nettlesere eller som er distribuert på servere som ikke støtter HTML5 history API. - MemoryRouter: Holder historikken til «URL-en» din i minnet (en matrise med URL-er). Nyttig i miljøer som React Native og testing.
Velg den rutertypen som passer best til applikasjonens krav og miljø.
Konklusjon
React Router v6 tilbyr en omfattende og fleksibel rutingsløsning for React-applikasjoner. Ved å forstå og anvende navigeringsmønstrene som er diskutert i dette blogginnlegget, kan du bygge robuste, brukervennlige og vedlikeholdbare webapplikasjoner. Fra deklarativ ruting med <Routes>
og <Route>
til dynamiske ruter med URL-parametere, programmatisk navigering med useNavigate
, og effektive datainnlastingsstrategier, gir React Router v6 deg kraften til å skape sømløse navigasjonsopplevelser for brukerne dine. Vurder å utforske avanserte rutingsbiblioteker og SSR/SSG-rammeverk for enda større kontroll og ytelsesoptimalisering. Husk å tilpasse disse mønstrene til dine spesifikke applikasjonskrav og alltid prioritere en klar og intuitiv brukeropplevelse.