useParams and Dynamic Routes
Bianca Charlotin
Posted on December 9, 2021
Intro
This post will discuss how to use useParams
to create dynamic routes with your React application. While working on my first React application, I had a complex time understanding useParams
and its use, even with my trusty friend Google. So I'm writing this blog post to help the next person who goes down this rabbit hole.
What is useParams
?
In the most basic definition useParams
is a React Hook that allows you to extract parameters from the URL in one line.
How To Use useParams
I will be using examples from my react App. to demonstrate how I used the hook. So let me clue you in on it:
I built a task manager App that has projects, and those projects have tasks.
I had a "/project"
route with the child component of Tasks. I wanted each of these projects to render its own tasks using dynamic URLs. Meaning, I wanted Project 1's Tasks to display a URL that looks like this "/projects/1/tasks"
without having to do so explicitly.
App.js File Declaring my Routes
import { Route, Routes } from 'react-router-dom';
import PageLayout from './components/layout/PageLayout';
export default function App() {
return (
<div >
<Routes>
<Route path="projects/*" element={<PageLayout />} />
</Routes>
</div>
);
}
In the code above, I have declared my routes "projects/*"
, which will render the <PageLayout />
component. Looking at the path carefully, you see an /*
at the end. The asterisk at the end means that all routes that look like projects/
will be handled by the PageLayout component
PageLayout Component: Setting Up Dynamic Routes
<PageLayout />
display is where I have the layout template used for all other routes declared and components imported, which means this component is the template for my other pages.
PageLayout Component:
import { Route, Routes } from 'react-router-dom';
import ProjectDisplay from '../projects/ProjectDisplay';
import ProjectInput from '../projects/ProjectInput'
import ProjectUpdate from '../projects/ProjectUpdate';
import TaskDisplay from '../tasks/TaskDisplay'
export default function PageLayout() {
return(
<div>
<Routes>
<Route path="/" element={<ProjectDisplay />} />
<Route path="new" element={<ProjectInput />} />
<Route path=":id/edit" element={<ProjectUpdate />} />
<Route path=":id/tasks" element={<TaskDisplay />} />
</Routes>
</div>
)
}
Let look at each route
<Route path="/" element={<ProjectDisplay />} />
. I have declared this URL structure: "projects/". renders all my projects.<Route path="new" element={<ProjectInput />} />
I have declared this URL structure: "projects/new", renders my project form for new project creation.
Dynamic Routes:
<Route path=":id/edit" element={<ProjectUpdate />} />
<Route path=":id/tasks" element={<TaskDisplay />} />
The colon indicates to React that this will be a dynamic route, I put "id" after because I decided that is what I'm passing in, but it can be called anything, ex::name
,:project_id
. Just make sure you're consistent.
Where are Dynamic Routes Getting Their Parameters?
Naturally, where I'm displaying all my projects is the most natural choice for me. I linked all project names to their corresponding tasks and sent the parameters through those links.
Below is my <ProjectDisplay />
code:
export default function ProjectDisplay() {
return(
<div>
{projects.map(p => {
<Link to={`/projects/${p.id}/tasks`}>{p.title}
</Link>
})}
</div>
)}
Above I am iterating over a projects array in this code to display all projects. I have established a link. Looking at the links pathway /projects/${p.id}/tasks
you see that for <Route path=":id/tasks" element={<TaskDisplay />} />
that we declared earlier we are passing in the full URL, but instead of the :id
we are passing in the projects id. Passing in this information is how your URLs go from: /projects/:id/tasks
to /projects/1/tasks
Extracting The Parameters Sent!
I'm going to be calling the hook useParams
on whichever component I have established the dynamic route for. In the example above, I linked my project page to go to the task page/<TaskDisplay />
component.
TaskDisplay Component:
The reason I sent the id
of my projects is because each project has a different set of tasks. To find and display these tasks:
- I need to know what project URL im on, and find that projects task
import { useParams } from 'react-router';
export default function TaskDisplay() {
const { id } = useParams()
const useParamsProjectId = parseInt(id)
const allTasks = useSelector(state => state.tasks)
const projectTasks = allTasks.filter((task) => (task.project_id === useParamsProjectId))
return(
)
...
}
const { id } = useParams()
: Declared a variable using the destructured value ofuseParmas
.{ id }
is the name I gave my dynamic route `.const useParamsProjectId = parseInt(id)
: Declared a variable which returnsid
that has been converted into an integer to use to compare later.const allTasks = useSelector(state => state.tasks)
: Here I am Grabbing all tasks fromstate
(independent of the project) and setting it equal to a variable calledalltasks
const projectTasks = allTasks.filter((task) => (task.project_id === useParamsProjectId))
: I'm using the methodfilter()
to return a new array with all tasks that'sproject_id
matches theuseParams id
akauseParamsProjectId
and setting it equal to a variable called projectTasks.
There you have it useParams
in full circle !
Posted on December 9, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.