Whenever you click on an interactive element on a webpage - a navbar button, login/signup button, a link to another page on the website, etc - it's likely that you'll be sent to a new URL. At the new URL, a new page will be rendered on the screen as dictated by data that was sent to your computer from a remote server. This is called routing, and although it may not always be apparent to the user, it can be carried out in two very different ways.
The traditional way to route a user after they've activated a navigational element on the page is called "server-side routing". In server-side routing, the site is designed such that only the data (ie, HTML) for the currently active page is sent to the client (your web browser). The bulk of the website (any pages that are not currently being displayed) remain stored on the server and are only accessed if and when a request for that specific page is made by the client. The client would then clear the prior page in order to display the new page that is being sent from the server.
While there are advantages to server-side routing, such as faster initial load times and simpler front-end design, it has its drawbacks. Although the initial load will be fast, any elements that are consistent across all pages (ie, a header/footer) will have to be re-delivered to the client and re-rendered. Perhaps most importantly, this re-rendering of the entire page breaks the smooth "single page web app" interface that has become the new standard for modern websites. Blank "loading" pages and long wait times between re-renders can be common with server-side routing. In order to build a seamless single-page web app in which routes are handled smoothly and only relevant page elements are re-rendered, client-side routing is required. Although technically more complex than the discrete pages provided by server-side routing, many tools have been created that make client-side routing nearly as simple as the alternative. For React apps, React Router is the go-to package for client-side routing.
Nested Routes with React Router
While React Router's core functionality is very useful for streamlining simple routing, it does a job that could be fairly easily accomplished by manually building a navbar, even by an early-career coder such as myself. The feature that really impresses me, however, is its use of nested routing. React Router leans into one of the key advantages of client-side routing - avoiding re-renders of reusable elements - and cleverly provides a simple interface that allows us to easily identify which elements should be displayed when. In the creator's words:
We've learned that most UI is a series of nested layouts that almost always map to segments of the URL so this idea is baked right in to React Router.
This is accomplished with nested routes. The setup couldn't be simpler:
- Nest "child" routes (Expenses, Invoices) within a "parent" route (App):
//main.jsx
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
<Route path="expenses" element={<Expenses />} />
<Route path="invoices" element={<Invoices />} />
</Route>
</Routes>
</BrowserRouter>
);
2. Add an "outlet" in the parent component to identify where the child components should be rendered:
//App.jsx
import { Outlet, Link } from "react-router-dom";
export default function App() {
return (
<div>
<h1>Bookkeeper</h1>
<nav
style={{
borderBottom: "solid 1px",
paddingBottom: "1rem",
}}
>
<Link to="/invoices">Invoices</Link> |{" "}
<Link to="/expenses">Expenses</Link>
</nav>
<Outlet />
</div>
);
}
With the above code (copied from React Router's v6 tutorial), the App component (containing nav bar and header) is always on display, while the Invoices and Expenses components are displayed conditionally, depending on what parameters are present in the URL. This simple solution avoids a mountain of headaches, and allows for a smoother, faster interface. What's not to love?
Top comments (0)