Let’s build a version of tiny react-router
I kept wondering: how does React Router actually work?
Not the full beast—just the core magic. So I built a tiny version. No dependencies. Just React + browser APIs.
Let’s go.
The Plan: Two Components Only
<Router />→ declares routes<Link />→ navigates without reloads
That’s it.
The Core: <Route />
It watches the URL and renders the matching component.
const Route = ({ path, component }) => {
const [currentPath, setCurrentPath] = useState(window.location.pathname);
useEffect(() => {
const onNavigate = () => setCurrentPath(window.location.pathname);
window.addEventListener("popstate", onNavigate);
window.addEventListener("navigation", onNavigate);
return () => {
window.removeEventListener("popstate", onNavigate);
window.removeEventListener("navigation", onNavigate);
};
}, []);
return path === currentPath ? component() : null;
};
Listens to popstate (back/forward) and a custom navigation event.
The Trick: <Link />
Prevents full reload. Pushes new path. Triggers update.
const Link = ({ path, children }) => {
const handleClick = (e) => {
e.preventDefault();
// pushing to address bar & avoiding entire page reload
window.history.pushState({}, "", path);
window.dispatchEvent(new CustomEvent("navigation"));
};
return <a href={path} onClick={handleClick}>{children}</a>;
};
pushState updates the URL.
dispatchEvent tells everyone: “Hey, path changed!”
The Pages
const Home = () => (
<>
<Link path="/about">About</Link>
<p>Home sweet home.</p>
</>
);
const About = () => (
<>
<Link path="/">Back Home</Link>
<p>You found the secret page.</p>
</>
);
Glue It Together
export default function App() {
return (
<>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</>
);
}
The Aha Moment
React Router isn’t magic.
It’s just:
- Watch URL changes (
popstate) - Update URL without reload (
pushState) - Trigger re-render (custom event)
That’s the entire trick.
Here’s the complete code link