JavaScript and React course Β· Module 6: React Router
Routing Configuration in Space Applications
In this lesson8
In the previous module, we learned the basics of React Router as an interplanetary navigation system. Now we'll dive deeper into the details of routing configuration in different types of space applications, both small and complex multi-module systems.
Different Types of Routers in React Router
React Router provides several types of routers that we can use depending on the environment in which our application runs:
1. BrowserRouter
BrowserRouter uses the HTML5 History API and is the most commonly used router in modern web applications. It creates clean, nice URLs without a hash (#):
1import { BrowserRouter } from 'react-router-dom';
2
3function App() {
4 return (
5 <BrowserRouter>
6 {/* Routing components */}
7 </BrowserRouter>
8 );
9}Important: BrowserRouter requires proper server configuration that must redirect all requests to the index.html file (to handle page refreshing and direct access to subpages).
2. HashRouter
HashRouter uses the hash function in the URL (the part after #). This is a simpler solution that doesn't require server configuration, but creates less elegant URLs:
1import { HashRouter } from 'react-router-dom';
2
3function App() {
4 return (
5 <HashRouter>
6 {/* Routing components */}
7 </HashRouter>
8 );
9}Example URLs when using HashRouter: /#/mars, /#/jupiter
3. MemoryRouter
MemoryRouter stores the navigation history in memory (doesn't use the browser URL). It's useful for tests and applications running in environments without a browser:
1import { MemoryRouter } from 'react-router-dom';
2
3function App() {
4 return (
5 <MemoryRouter initialEntries={['/mars', '/jupiter']} initialIndex={1}>
6 {/* Routing components */}
7 </MemoryRouter>
8 );
9}Advanced Route Configuration
The Route component offers more options than just basic path-to-element mapping:
1. Dynamic Paths with Parameters
1<Route path="/planet/:planetId" element={<PlanetDetails />} />This path matches URLs like /planet/mars, /planet/jupiter, etc. The :planetId parameter is dynamic and can be read in the component.
2. Optional Paths
1<Route path="/missions/:year?/:month?" element={<MissionsList />} />Question marks indicate optional parameters. This path matches URLs:
/missions(without parameters)/missions/2150(year only)/missions/2150/06(year and month)
3. Wildcard Parameters (catch-all)
1<Route path="/files/*" element={<FileExplorer />} />The asterisk catches everything after /files/, e.g., /files/documents/reports/annual.pdf.
Routing Structure for Larger Space Applications
In extensive space applications, routing can become complex. Here's how you can organize it:
1. Nested Routes
We can nest routes to create a hierarchical structure:
1function AppRoutes() {
2 return (
3 <Routes>
4 <Route path="/" element={<SpaceLayout />}>
5 <Route index element={<Dashboard />} />
6 <Route path="planets" element={<PlanetLayout />}>
7 <Route index element={<PlanetsList />} />
8 <Route path=":planetId" element={<PlanetDetails />} />
9 </Route>
10 <Route path="missions" element={<MissionLayout />}>
11 <Route index element={<MissionsDashboard />} />
12 <Route path="scheduled" element={<ScheduledMissions />} />
13 <Route path="completed" element={<CompletedMissions />} />
14 </Route>
15 </Route>
16 <Route path="/auth" element={<AuthLayout />}>
17 <Route path="login" element={<Login />} />
18 <Route path="register" element={<Register />} />
19 </Route>
20 <Route path="*" element={<NotFound />} />
21 </Routes>
22 );
23}In the example above:
SpaceLayoutis the main layout for paths starting with "/"PlanetLayoutis the layout for all paths in the "planets" section- The
indexelement specifies what should be rendered for the parent path (e.g., "/planets")
2. Route element vs. component
Since React Router v6 we use the element prop instead of component from earlier versions:
1// React Router v6 and newer (v7, v8)
2<Route path="/mars" element={<MarsBase />} />
3
4// React Router v5 (older)
5<Route path="/mars" component={MarsBase} />Why is this important? The element syntax allows passing a rendered element, which provides greater flexibility:
1<Route
2 path="/mars"
3 element={
4 <MarsBase
5 temperature={-60}
6 oxygenLevel="low"
7 waterAvailable={true}
8 />
9 }
10/>3. Outlet - Displaying Sub-route Components
The Outlet component specifies where in the parent component the sub-route components should be rendered:
1import { Outlet } from 'react-router-dom';
2
3function SpaceLayout() {
4 return (
5 <div className="space-layout">
6 <header>
7 <h1>Interplanetary Navigation System</h1>
8 <nav>{/* Navigation links */}</nav>
9 </header>
10
11 <main>
12 {/* Sub-route components will be rendered here */}
13 <Outlet />
14 </main>
15
16 <footer>
17 <p>Space Command Center © 2150</p>
18 </footer>
19 </div>
20 );
21}Configuration with Error Handling
A good practice is to add global error handling to our routing system:
1function AppRoutes() {
2 return (
3 <Routes>
4 <Route path="/" element={<SpaceLayout />} errorElement={<GlobalError />}>
5 {/* Other routes */}
6 </Route>
7 </Routes>
8 );
9}
10
11function GlobalError() {
12 const error = useRouteError();
13
14 return (
15 <div className="error-container">
16 <h1>Houston, we have a problem!</h1>
17 <p>An error occurred in the navigation system:</p>
18 <pre>{error.message || "Unknown error"}</pre>
19 <button onClick={() => window.location.href = "/"}>
20 Return to Command Center
21 </button>
22 </div>
23 );
24}Full Configuration Example for a Complex Space Application
Below is a comprehensive example of routing configuration for an advanced application:
1import {
2 BrowserRouter,
3 Routes,
4 Route,
5 Outlet,
6 Navigate,
7 useRouteError
8} from 'react-router-dom';
9
10// Layouts
11function MainLayout() {
12 return (
13 <div className="main-layout">
14 <MainNavigation />
15 <div className="content">
16 <Outlet />
17 </div>
18 <Footer />
19 </div>
20 );
21}
22
23function AuthLayout() {
24 return (
25 <div className="auth-layout">
26 <div className="auth-container">
27 <Outlet />
28 </div>
29 </div>
30 );
31}
32
33// Error Components
34function GlobalError() {
35 const error = useRouteError();
36 return (
37 <div className="error-screen">
38 <h1>Navigation System Error</h1>
39 <p>{error.message || "Unknown error"}</p>
40 </div>
41 );
42}
43
44function NotFound() {
45 return (
46 <div className="not-found">
47 <h1>Lost in Outer Space</h1>
48 <p>The ship could not find the requested location.</p>
49 </div>
50 );
51}
52
53// Protected Route Component
54function ProtectedRoute({ children }) {
55 const isAuthenticated = useAuth();
56
57 if (!isAuthenticated) {
58 return <Navigate to="/auth/login" replace />;
59 }
60
61 return children;
62}
63
64// Main App
65function App() {
66 return (
67 <BrowserRouter>
68 <Routes>
69 {/* Main section with layout */}
70 <Route path="/" element={<MainLayout />} errorElement={<GlobalError />}>
71 <Route index element={<Dashboard />} />
72
73 {/* Planets */}
74 <Route path="planets">
75 <Route index element={<PlanetsList />} />
76 <Route path=":planetId" element={<PlanetDetails />} />
77 </Route>
78
79 {/* Missions - require authentication */}
80 <Route path="missions" element={
81 <ProtectedRoute>
82 <MissionsLayout />
83 </ProtectedRoute>
84 }>
85 <Route index element={<MissionsDashboard />} />
86 <Route path="new" element={<NewMission />} />
87 <Route path=":missionId" element={<MissionDetails />} />
88 <Route path=":missionId/edit" element={<EditMission />} />
89 </Route>
90
91 {/* Crew */}
92 <Route path="crew">
93 <Route index element={<CrewList />} />
94 <Route path=":memberId" element={<CrewMemberProfile />} />
95 </Route>
96
97 {/* Settings - require authentication */}
98 <Route path="settings" element={
99 <ProtectedRoute>
100 <Settings />
101 </ProtectedRoute>
102 } />
103 </Route>
104
105 {/* Authentication section */}
106 <Route path="/auth" element={<AuthLayout />}>
107 <Route path="login" element={<Login />} />
108 <Route path="register" element={<Register />} />
109 <Route path="forgot-password" element={<ForgotPassword />} />
110 <Route path="reset-password/:token" element={<ResetPassword />} />
111 </Route>
112
113 {/* Public documentation */}
114 <Route path="/docs/*" element={<DocsLayout />} />
115
116 {/* Redirect from old path to new one */}
117 <Route path="/old-missions" element={<Navigate to="/missions" replace />} />
118
119 {/* 404 handling */}
120 <Route path="*" element={<NotFound />} />
121 </Routes>
122 </BrowserRouter>
123 );
124}React Router Configuration in Development Environment
When developing a space application, it's worth configuring development tools to work with React Router:
1. React Router DevTools
1// Only in development mode
2if (process.env.NODE_ENV === 'development') {
3 const ReactRouterDevTools = React.lazy(() =>
4 import('react-router-devtools').then(module => ({
5 default: module.ReactRouterDevTools
6 }))
7 );
8
9 // Usage in the application
10 <React.Suspense fallback={null}>
11 <ReactRouterDevTools />
12 </React.Suspense>
13}2. webpack-dev-server Configuration for BrowserRouter
To handle page refreshing in the development environment with BrowserRouter, you need to configure webpack-dev-server:
1// webpack.config.js
2module.exports = {
3 // other settings...
4 devServer: {
5 historyApiFallback: true, // Redirect 404 to index.html
6 // other settings...
7 }
8};Production Server Configuration for React Router
In the production environment, the server must be configured to handle all React Router paths:
1. For Node.js/Express server:
1const express = require('express');
2const path = require('path');
3const app = express();
4
5// Serving static files
6app.use(express.static(path.join(__dirname, 'build')));
7
8// All requests that are not for static files are redirected to index.html
9app.get('*', (req, res) => {
10 res.sendFile(path.join(__dirname, 'build', 'index.html'));
11});
12
13const PORT = process.env.PORT || 3000;
14app.listen(PORT, () => {
15 console.log(`Server listening on port ${PORT}`);
16});2. For Apache server (.htaccess):
1<IfModule mod_rewrite.c>
2 RewriteEngine On
3 RewriteBase /
4 RewriteRule ^index\.html$ - [L]
5 RewriteCond %{REQUEST_FILENAME} !-f
6 RewriteCond %{REQUEST_FILENAME} !-d
7 RewriteRule . /index.html [L]
8</IfModule>3. For Nginx server:
1server {
2 listen 80;
3 server_name space-application.com;
4
5 root /var/www/html;
6 index index.html;
7
8 location / {
9 try_files $uri $uri/ /index.html;
10 }
11}Summary
Proper routing configuration is crucial for the functioning of a space application (React). Key points:
- Choose the right router type - usually
BrowserRouterfor modern applications - Create hierarchical route structures - use nested routes with
Outletfor better organization - Implement error handling - use
errorElementfor error handling - Secure private routes - create a
ProtectedRoutecomponent to protect access - Configure the production server - make sure the server redirects all requests to index.html
With a well-configured navigation system, users of your space application will be able to freely travel between its different parts, without worrying about getting lost in outer space (404 errors).
Code for this lesson: App.jsx
1import React from 'react';
2import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
3
4// Home page
5function Home() {
6 return (
7 <div className="page home">
8 <h1>Home page</h1>
9 <p>Welcome to the space navigation center!</p>
10 <p>Use the menu above to navigate between pages.</p>
11 </div>
12 );
13}
14
15// "About" page
16function About() {
17 return (
18 <div className="page about">
19 <h1>About</h1>
20 <p>We are a team of space explorers.</p>
21 <p>Our mission: exploring the galaxy with React Router!</p>
22 </div>
23 );
24}
25
26// Contact page
27function Contact() {
28 return (
29 <div className="page contact">
30 <h1>Contact</h1>
31 <p>Email: mission-control@space.com</p>
32 <p>Phone: +48 123 456 789</p>
33 </div>
34 );
35}
36
37// Nawigacja
38function Navigation() {
39 return (
40 <nav className="navigation">
41 <Link to="/" className="nav-link">Home</Link>
42 <Link to="/about" className="nav-link">About</Link>
43 <Link to="/contact" className="nav-link">Contact</Link>
44 </nav>
45 );
46}
47
48function App() {
49 return (
50 <BrowserRouter>
51 <div className="app">
52 <header>
53 <h2>Space Navigator</h2>
54 <Navigation />
55 </header>
56
57 <main>
58 <Routes>
59 <Route path="/" element={<Home />} />
60 <Route path="/about" element={<About />} />
61 <Route path="/contact" element={<Contact />} />
62 </Routes>
63 </main>
64 </div>
65 </BrowserRouter>
66 );
67}
68
69export default App;Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What is the main difference between BrowserRouter and HashRouter?
Hands-on tasks in the game
- Click in order
Arrange the React Router installation command:
- Code editor
Create: <BrowserRouter><Routes><Route path='/' element={<Dashboard />} /><Route path='/planets' element={<Planets />} /><Route path='/missions' element={<Missions />} /></Routes></BrowserRouter>. Add <Link to='/planets'>Planets</Link>!
- Click in order
Arrange the basic React Router application structure:
- Code editor
Create navigation: <nav><NavLink to='/' className={({isActive}) => isActive ? 'active' : ''}>Home</NavLink><NavLink to='/asteroids'>Asteroids</NavLink></nav>. Add CSS: .active { color: gold; border-bottom: 2px solid gold }