Lab 21: Route Parameters
Objectives
- Navigate to a route with a parameter
Steps
Navigate to a route with a parameter
Add a
find
method toprojectAPI
to return a singleProject
byid
src\projects\projectAPI.js
const projectAPI = {
...
+ find(id) {
+ return fetch(`${url}/${id}`)
+ .then(checkStatus)
+ .then(parseJSON);
+ },
+
...
};Create the files below and add the code for these pre-built components we will use in this lab. Take a moment to review the code in them.
src\projects\ProjectDetail.js
import React from 'react';
import { Project } from './Project';
export default function ProjectDetail({ project }) {
return (
<div className="row">
<div className="col-sm-6">
<div className="card large">
<img
className="rounded"
src={project.imageUrl}
alt={project.name}
/>
<section className="section dark">
<h3 className="strong">
<strong>{project.name}</strong>
</h3>
<p>{project.description}</p>
<p>Budget : {project.budget}</p>
<p>Signed: {project.contractSignedOn.toLocaleDateString()}</p>
<p>
<mark className="active">
{' '}
{project.isActive ? 'active' : 'inactive'}
</mark>
</p>
</section>
</div>
</div>
</div>
);
}src\projects\ProjectPage.js
import React, { useEffect, useState } from 'react';
import { projectAPI } from './projectAPI';
import ProjectDetail from './ProjectDetail';
import { Project } from './Project';
import { useParams } from 'react-router-dom';
function ProjectPage(props) {
const [loading, setLoading] = useState(false);
const [project, setProject] = useState(null);
const [error, setError] = useState(null);
const params = useParams();
const id = Number(params.id);
useEffect(() => {
setLoading(true);
projectAPI
.find(id)
.then((data) => {
setProject(data);
setLoading(false);
})
.catch((e) => {
setError(e);
setLoading(false);
});
}, [id]);
return (
<div>
<>
<h1>Project Detail</h1>
{loading && (
<div className="center-page">
<span className="spinner primary"></span>
<p>Loading...</p>
</div>
)}
{error && (
<div className="row">
<div className="card large error">
<section>
<p>
<span className="icon-alert inverse "></span> {error}
</p>
</section>
</div>
</div>
)}
{project && <ProjectDetail project={project} />}
</>
</div>
);
}
export default ProjectPage;Add a route to display the
ProjectPage
(notice that we now have aProjectPage
and aProjectsPage
so be careful you are in the correct file).src\App.js
import ProjectsPage from './projects/ProjectsPage';
+ import ProjectPage from './projects/ProjectPage';
function App() {
return (
<Router>
<header className="sticky">
<span className="logo">
<img src="/assets/logo-3.svg" alt="logo" width="49" height="99" />
</span>
<NavLink to="/" className="button rounded">
<span className="icon-home"></span>
Home
</NavLink>
<NavLink to="/projects/" className="button rounded">
Projects
</NavLink>
</header>
<div className="container">
<Routes>
<Route path="/" element={HomePage} />
<Route path="/projects" element={ProjectsPage} />
+ <Route path="/projects/:id" element={<ProjectPage />} />
</Routes>
</div>
</Router>
);
}Make the name and description clickable by adding a
<Link />
component around them.src\projects\ProjectCard.js
+ import { Link } from 'react-router-dom';
...
<section className="section dark">
+ <Link to={'/projects/' + project.id}>
<h5 className="strong">
<strong>{project.name}</strong>
</h5>
<p>{formatDescription(project.description)}</p>
<p>Budget : {project.budget.toLocaleString()}</p>
+ </Link>
<button
type="button"
className=" bordered"
onClick={() => {
handleEditClick(project);
}}
>
<span className="icon-edit "></span>
Edit
</button>
</section>
...Verify the new route works by the following these steps:
- Visit the root of the site:
http://localhost:3000/
and refresh the page in your browser. - Click on
Projects
in the navigation. - Verify you are taken to the
/projects
route and theProjectsPage
displays. - Click on the name or description in any of the project cards .
- Verify you are taken to the
/projects/1
route and theProjectPage
displays theProjectDetail
component.
<
- Visit the root of the site: