跪拜 Guibai
← All articles
Frontend

React Router v7: Route Tables Become Component Trees

By 凌涘 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Component-based routing collapses route config, parameter parsing, and layout nesting into a single declarative tree. Teams avoid writing and maintaining the same boilerplate — URL splitting, active link states, nested layout wrappers — across every page, and code splitting becomes a one-line change that doesn't touch the route definitions.

Summary

A hand-written HashRouter uses a flat key-value object for routes, but real applications quickly hit limits: nested layouts, URL parameter parsing, and code splitting all require custom code. React Router v7 addresses these by turning the route table into a component tree where `<Route>` nesting mirrors UI nesting. Dynamic segments like `:id` are extracted automatically via the `useParams` hook, and `<Outlet>` marks where child routes render inside a parent layout, eliminating repeated wrapper components. Navigation moves from raw `<a>` tags to `<Link>` and `useNavigate`, which update the URL through the History API without full page reloads. Lazy loading slots in through React's `lazy` and `Suspense`, splitting pages into separate chunks that download only when a route matches. The shift is from imperative routing — listen, parse, look up, call — to a declarative structure where the configuration itself documents the mapping from path to component.

Takeaways
Route configuration moves from a flat object to nested `<Route>` components, so path hierarchy and UI hierarchy stay in sync without a separate mapping table.
Dynamic path segments like `/user/:id` are extracted with the `useParams` hook; the parameter name in the path becomes the variable name in the component.
`<Outlet>` renders child route content inside a parent layout, so shared chrome like headers and sidebars is written once and inherited by nested pages.
`<Link>` replaces raw `<a>` tags, intercepting clicks to push History API state instead of triggering full-page navigation.
`useNavigate` provides programmatic redirects that stay client-side, unlike `window.location.href` which reloads the entire page.
Lazy loading pages uses React's `lazy` and `Suspense`; the route config itself doesn't change, and chunks download only when their route is first visited.
A wildcard `path="*"` at the end of `<Routes>` catches all unmatched URLs for a 404 fallback.
Conclusions

The jump from imperative to declarative routing isn't about new capabilities — hand-written routers can do nesting, params, and lazy loading — but about removing repetitive plumbing that accumulates across pages.

React Router's design keeps routing concerns layered: the declaration layer describes what maps to what, the navigation layer handles how transitions fire, and the data layer feeds URL state into components, so each layer can change independently.

Code splitting via `lazy` is transparent to the route definitions, which means a project can start with eager-loaded pages and add splitting later without rewriting any route configuration.

Concepts & terms
Declarative routing
Describing what the route structure is (path, component, nesting) in JSX rather than imperatively coding how to listen for URL changes, parse parameters, and call render functions.
useParams
A React Router hook that extracts dynamic path segments (like `:id` from `/user/:id`) as an object, matching by parameter name rather than by index position in a split string.
Outlet
A React Router component that acts as a placeholder in a parent route's layout where matched child route content gets rendered, enabling nested layouts without repeating wrapper components.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗