Heroes App uses React Router v6 with aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ludwiigdev/Heroes_App/llms.txt
Use this file to discover all available pages before exploring further.
HashRouter at its root and a deliberate two-level route architecture: a top-level AppRouter that splits traffic between public and private zones, and a nested HeroesRoutes that handles all the feature pages behind authentication. Understanding how these layers compose — and why a hash-based router was chosen — is the key to navigating (pun intended) the codebase.
Why HashRouter?
Most React SPAs useBrowserRouter, which relies on the HTML5 History API and clean URLs like /marvel. The catch is that on a static host (Netlify, GitHub Pages, S3), a user who refreshes the browser or pastes a deep link directly into the address bar triggers a real HTTP request for that path — and the server returns a 404 because the file doesn’t exist.
HashRouter sidesteps this entirely by placing the application path after a # in the URL (e.g., /#/marvel). The browser never sends the fragment to the server, so every request lands on index.html and React Router handles the rest.
If you ever migrate to a server that supports URL rewriting (Vercel, a custom Express server, etc.) you can swap
HashRouter for BrowserRouter without changing any route definitions. The _redirects file described below handles the Netlify case if you prefer clean URLs.The _redirects File
For deployments that prefer clean URLs over hash URLs, a _redirects file in the public/ directory instructs Netlify (and compatible CDNs) to serve index.html for every path that doesn’t match a static asset:
/marvel, /dc, and /hero/dc-batman all resolve to the SPA, with React Router then handling the in-app navigation.
Route Table
The following table lists every navigable path in the application, which component renders it, and whether it is guarded.| Path | Component | Guard | Notes |
|---|---|---|---|
/login | LoginPage | PublicRoute | Redirects to /marvel if already logged in |
/marvel | MarvelPage | PrivateRoute | Lists all Marvel heroes |
/dc | DcPage | PrivateRoute | Lists all DC Comics heroes |
/search | SearchPage | PrivateRoute | Accepts ?q= query param |
/hero/:id | HeroPage | PrivateRoute | :id is a hero id like dc-batman |
/ | (redirect) | PrivateRoute | Immediately navigates to /marvel |
Two-Level Router Architecture
The routing is intentionally split into two files with clearly separated responsibilities.Level 1 — AppRouter
AppRouter is the gatekeeper. It knows about exactly two routes: the public login page and everything else. “Everything else” is delegated wholesale to HeroesRoutes, wrapped in PrivateRoute.
/* wildcard ensures that any path other than /login is captured and passed to PrivateRoute. If the user is not logged in, they are redirected to /login before HeroesRoutes ever mounts.
Level 2 — HeroesRoutes
HeroesRoutes renders the persistent Navbar and then a nested <Routes> block for the actual content pages. It only ever mounts if PrivateRoute has already confirmed the user is authenticated.
Because
HeroesRoutes is rendered under the /* wildcard in AppRouter, the paths here are relative — marvel matches /#/marvel, not /#/marvel/marvel.Component tree overview
Route Guards
Both guards are thin wrappers that readlogged from AuthContext and either render children or issue a redirect.
PrivateRoute
Renders
children when logged === true. Otherwise it saves the attempted path to localStorage as "lastPath" and redirects to /login.PublicRoute
Renders
children when logged === false. An authenticated user who visits /login is immediately bounced to /marvel.lastPath redirect flow, see the Authentication concept page.
Dynamic Route: /hero/:id
HeroPage uses the :id URL parameter to look up a specific hero from the in-memory dataset.
id parameter follows the convention {publisher-slug}-{hero-slug} (e.g., dc-batman, marvel-spider). If getHeroById returns undefined — because someone typed a non-existent id in the URL — the page falls back to /marvel rather than crashing.
For a full breakdown of hero ids and the helper functions, see the Hero Data concept page.
Navigation with NavLink
TheNavbar component uses React Router’s NavLink instead of plain Link so it can apply an active CSS class to the currently matched route.
NavLink’s className prop accepts a function that receives { isActive } — this is a React Router v6 API that replaces the v5 activeClassName prop. The ternary injects the Bootstrap active class when the route matches.