This challenge focuses on creating nested routes using React Router, including
dynamic segments that enable you to show details for a specific item (like
a movie). You will use useParams to capture route parameters
from the URL, and you'll nest routes so your UI can display multiple levels
of content.
By the end, you will be able to:
/movies/:movieId) to show details for
the selected movie.useParams for extracting route parameters from the
URL path.movie_data.js) into your app./movies route, pointing to /movies/:movieId.<Outlet />.<NavLink /> entries.
Use relative paths like to={String(movieId)}.Movies component before the
<Outlet />.movie_details.jsx),
call useParams() to grab the movieId..find to locate the chosen movie in the dataset
and render its details (title, description, etc.).Below is a basic implementation. We will assume a minimal folder structure. Notice how we avoid spaces or hyphens in filenames, using underscores instead:
my_react_app/
package.json
src/
index.js
app.jsx
router.jsx
data/
movie_data.js
components/
layout.jsx
movies/
movies.jsx
movie_details.jsx
movie_nav_bar.jsx
...
public/
index.html
...
Follow these file examples and adapt to your own project setup. Each code snippet below includes pseudocode comments, expected input, and expected output for clarity.
// Basic movie data array
// Expected Input: none, this file just exports data
// Expected Output: An array of movie objects with id, title, and description
export const movies = [
{
id: 1,
title: 'The Informer',
description: 'A suspenseful crime drama with unexpected twists.'
},
{
id: 2,
title: 'Lost in Space',
description: 'A sci-fi family adventure beyond the stars.'
},
{
id: 3,
title: 'Treasure Island',
description: 'A classic tale of pirates and hidden gold.'
}
];
// MovieDetails component using useParams
// Expected Input: a 'movies' prop array, plus a URL parameter for movieId
// Expected Output: displays the details (title, description) of the selected movie
import React from 'react';
import { useParams } from 'react-router-dom';
function Movie_Details({ movies }) {
// <-- Pseudocode: we extract the movieId from the URL via useParams
const { movieId } = useParams();
console.log('Movie ID from URL:', movieId); // for debugging
// <-- Convert the movieId to a number for accurate comparison
const idNumber = parseInt(movieId, 10);
// <-- Find the movie that matches the id
const movieChoice = movies.find((movie) => movie.id === idNumber);
// <-- If not found, render a 'Movie not found' message
if (!movieChoice) {
return <h2>Movie not found</h2>;
}
return (
<div>
<h1>{movieChoice.title}</h1>
<p>{movieChoice.description}</p>
</div>
);
}
export default Movie_Details;
// MovieNavBar component
// Expected Input: a 'movies' prop (array of movie objects)
// Expected Output: a nav of links for each movie (links to /movies/:movieId)
import React from 'react';
import { NavLink } from 'react-router-dom';
function Movie_Nav_Bar({ movies }) {
// <-- Pseudocode: create a nav bar for each movie
return (
<nav>
<ul>
{movies.map((movie) => (
<li key={movie.id}>
<NavLink
to={String(movie.id)}
style={({ isActive }) => ({
fontWeight: isActive ? 'bold' : 'normal'
})}
>
{movie.title}
</NavLink>
</li>
))}
</ul>
</nav>
);
}
export default Movie_Nav_Bar;
// Movies component with nested Outlet
// Expected Input: a 'movies' prop (array of movie objects)
// Expected Output: Renders the main 'Movies Component' text, a nav bar, and the child route
import React from 'react';
import { Outlet } from 'react-router-dom';
import Movie_Nav_Bar from './movie_nav_bar';
function Movies({ movies }) {
// <-- Pseudocode: Display a heading and a nav bar for movie links
// Then use <Outlet /> for any nested route to show details
return (
<div>
<h1>Movies Component</h1>
<Movie_Nav_Bar movies={movies} />
<!-- Child route content (MovieDetails) will render here -->
<Outlet />
</div>
);
}
export default Movies;
// App component hooking up the router
// Expected Input: none, but provides the entire app
// Expected Output: the RouterProvider with all the routes
// We'll import 'movies' data here and pass to routes
import React from 'react';
import { RouterProvider } from 'react-router-dom';
import router from './router';
function App() {
// <-- Pseudocode: Provide the router to the entire app
return <RouterProvider router={router} />;
}
export default App;
// Router Setup with nested routes
// We pass 'movies' to the 'Movies' and 'Movie_Details' components
import React from 'react';
import { createBrowserRouter } from 'react-router-dom';
// Layout and pages
import Layout from './components/layout';
import Movies from './components/movies/movies';
import Movie_Details from './components/movies/movie_details';
// Other pages:
import Home from './components/home';
import Stocks from './components/stocks';
import { movies } from './data/movie_data';
const router = createBrowserRouter([
{
element: <Layout />,
children: [
{
path: '/',
element: <Home />
},
{
path: 'stocks',
element: <Stocks />
},
{
path: 'movies',
element: <Movies movies={movies} />,
// Nested route for individual movie details
children: [
{
path: ':movieId',
element: <Movie_Details movies={movies} />
}
]
},
{
path: '*',
element: <h1>Page Not Found</h1>
}
]
}
]);
export default router;
// Layout component for a global nav or structure
// Expected Input: none
// Expected Output: Renders a top-level layout with a nav plus an <Outlet /> for child routes
import React from 'react';
import { Outlet, NavLink } from 'react-router-dom';
function Layout() {
return (
<div className='app'>
<h1>App Component</h1>
<nav className="comp nav">
<ul>
<li>
<NavLink
to="/"
style={({ isActive }) => ({
fontWeight: isActive ? 'bold' : 'normal'
})}
>
Home
</NavLink>
</li>
<li>
<NavLink
to="/stocks"
style={({ isActive }) => ({
fontWeight: isActive ? 'bold' : 'normal'
})}
>
Stocks
</NavLink>
</li>
<li>
<NavLink
to="/movies"
style={({ isActive }) => ({
fontWeight: isActive ? 'bold' : 'normal'
})}
>
Movies
</NavLink>
</li>
</ul>
</nav>
<main>
<Outlet />
</main>
</div>
);
}
export default Layout;
// Very simple Home component
// Expected Input: none
// Expected Output: Renders a welcome message
import React from 'react';
function Home() {
return <h2>Welcome to the Home Page!</h2>;
}
export default Home;
// Simple Stocks component
// Expected Input: none
// Expected Output: Renders "Stocks Component"
import React from 'react';
function Stocks() {
return <h2>Stocks Component</h2>;
}
export default Stocks;
After placing these files, run your dev server (npm run dev
or npm start for some setups). Navigate to:
/ for Home/movies for the Movies list/movies/2 for "Lost in Space" details, as an example
You should see the nested route display the Movie_Details
component within the Movies component.
Basic Elementary Solution:
The above code is minimal, demonstrating the core idea of nested routes,
dynamic segments, and a simple usage of useParams.
More Advanced Adjustments:
movieId or
missing data (already shown in Movie_Details with a
"not found" fallback)./movies/:movieId/reviews/:reviewId for more details.
Think of nesting like a bookstore: the main “Movies” section is
one big category, but each movie inside has its own dedicated “aisle”
for details. useParams is your sign telling you which aisle
the user selected, allowing you to fetch or filter the relevant data
from your broader “catalog.”
Practical Applications:
/products/:id) or social platforms
(/profile/:username).This approach makes your code more organized and your user experience more intuitive.
Enjoy exploring nested routes in React Router, and feel free to add additional layers to practice advanced nesting, data fetching, and route guards.