Check your version
This post assumes you're using React Router v6. If not, find your version below.One thing I love about React Router is how composable it is. React Router doesn't give you a house - it gives you some nails, plywood, and a hammer and trusts that you can do the rest. A more technical way to say that is React Router gives you the routing primitives upon which you can build your app. This concept really shines when it comes to what we're going to do in this post – build our own custom Link
component.
What we want to do is create our own "old school" navbar. Basically what that means is we'll add a >
to the front of whatever Link
is . If our two routes were /
and /about
, the two states of our navbar would look like this
Before we dive into our custom Link
, let's build out the skeleton of our app. We'll have two components, Home
and About
, which will map to our two Route
s, /
and /about
.
import * as React from "react";import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";const Home = () => <h2>Home</h2>;const About = () => <h2>About</h2>;export default function App() {return (<Router><div>{/* Links */}<hr /><Routes><Route path="/" element={<Home />} /><Route path="/about" element={<About />} /></Routes></div></Router>);}
Now the reason we're here, implementing our custom Link
component. We'll call it OldSchoolMenuLink
. Let's start with the API and work backwards. Here's what it'll look like
export default function App() {return (<Router><div><OldSchoolMenuLink to="/">Home</OldSchoolMenuLink><OldSchoolMenuLink to="/about">About</OldSchoolMenuLink><hr/><Routes><Route path="/" element={<Home />}><Route path="/about" element={<About />}></Routes></div></Router>)}
Notice it's the OldSchoolMenuLink
that will be in charge of adding and removing the >
, but its API is the same as React Router's Link
component.
Now let's build it out. We know what props OldSchoolMenuLink
is going to be taking in, so we can build out the skeleton of the component before we worry about its implementation.
function OldSchoolMenuLink({ children, to }) {}
WTF is children?
If you're not familiar with the "children" prop in React, it's a placeholder for whatever is between the opening and closing element.
<Hover>Children can be anything</Hover><Hover>{true}</Hover><Hover>{() => console.log('Even functions')}</Hover>
Now the main question becomes, what is OldSchoolMenuLink
going to render? Remember, the whole point of this component is, based on the active route, to make this navbar UI work.
With that said, we know we're going to render a Link
and if the app's current location matches the Link
s to
prop, we'll pre-pend it with a >
.
In order to do that, we need to get the "app's current location". To do that we can use React Router's useLocation
Hook. From there, all we need to do is compare the location
's pathname
with the to
prop.
function OldSchoolMenuLink ({ children, to }) {const location = useLocation()const match = location.pathname === toreturn ()}
Now that we know if the app's current location matches the Link
s path, all that's left to do is render some UI, toggling the >
based on our match
variable.
function OldSchoolMenuLink({ children, to }) {const location = useLocation();const match = location.pathname === to;return (<div className={match ? "active" : ""}>{match ? "> " : ""}<Link to={to}>{children}</Link></div>);}
Just like that, we've created our own custom OldSchoolMenuLink
component by composing React Router's Link
component.