Demystify React Router by building the core idea in 30 lines: change the URL without reloading, render the matching view.
The mini-router
const routes = {
"/": () => `<h1>Home</h1>`,
"/about": () => `<h1>About</h1>`,
"/students": async () => renderList(await fetchStudents()),
};
function render(path) {
const view = routes[path] ?? (() => `<h1>404</h1>`);
Promise.resolve(view()).then((html) => (app.innerHTML = html));
}
// intercept link clicks
document.addEventListener("click", (e) => {
const a = e.target.closest("a[data-link]");
if (!a) return;
e.preventDefault();
history.pushState(null, "", a.href); // change URL, no reload
render(location.pathname);
});
// back/forward buttons
window.addEventListener("popstate", () => render(location.pathname));
render(location.pathname); // initialWhat the real routers add
- Dynamic segments (
/student/:id) via pattern matching - Nested routes, lazy loading, scroll restoration, focus management
The deployment gotcha
Refresh on /about asks the SERVER for /about โ which doesn't exist. Every SPA host needs the rewrite-to-index.html rule (Netlify's /* /index.html 200). Now you know why, not just what. Interview gold: "explain client-side routing" โ you just built it.