Route parameters and navigation
Every blog post should have its own page: /posts/1, /posts/2 and so on. You do not need a route for each post — one route with a parameter is enough. A parameter is a variable part of the path, marked with a colon: /posts/:id.
A route with a parameter
Add the route to src/App.jsx:
// src/App.jsx
import PostPage from './pages/PostPage.jsx';
// inside Routes:
<Route path="/posts/:id" element={<PostPage />} />This route matches /posts/1, /posts/42 and any other value in place of :id.
Reading the parameter
The page component reads parameters with the useParams hook. Create src/pages/PostPage.jsx:
// src/pages/PostPage.jsx
import { useParams } from 'react-router';
export default function PostPage() {
const { id } = useParams();
return <h1>Post No. {id}</h1>;
}Open http://localhost:5173/posts/7 — the page shows "Post No. 7". A parameter value is always a string: '7', not 7.
Loading the post by parameter
The parameter goes into the request address. With the useFetch hook from the custom hooks lesson:
// src/pages/PostPage.jsx
import { useParams } from 'react-router';
import { useFetch } from '../hooks/useFetch.js';
export default function PostPage() {
const { id } = useParams();
const { data: post, loading, error } = useFetch(
`https://jsonplaceholder.typicode.com/posts/${id}`,
);
if (loading) return <p>Loading…</p>;
if (error) return <p>Post not found</p>;
return (
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>
);
}The page /posts/7 shows the title and text of the seventh post. When the address changes, id changes and useFetch loads the new post.
Links to posts
In the post list the titles become links. In src/components/PostList.jsx:
// src/components/PostList.jsx
import { Link } from 'react-router';
// inside map:
<li key={post.id}>
<Link to={`/posts/${post.id}`}>{post.title}</Link>
</li>Click any title on the home page — the post page opens.
Navigating from code
Sometimes you navigate not on a link click but after an action: submitting a form, deleting. That is what the useNavigate hook is for:
// src/pages/PostPage.jsx
import { useNavigate } from 'react-router';
const navigate = useNavigate();
// in the markup:
<button onClick={() => navigate('/')}>All posts</button>
<button onClick={() => navigate(-1)}>Back</button>navigate('/') goes to the home page, navigate(-1) goes to the previous page in history, like the browser's Back button.
Query string parameters
For filters and search the query string is handy — /?page=2. It is read with the useSearchParams hook: const [searchParams] = useSearchParams(); and searchParams.get('page').
Common mistake
A parameter is a string, so a strict comparison with a number fails:
const { id } = useParams();
// Wrong: '7' === 7 is false.
const post = posts.find((item) => item.id === id);
// Correct:
const post = posts.find((item) => item.id === Number(id));Convert the parameter to a number when comparing it with numeric ids.