DEV Community

Cover image for useParams and Dynamic Routes
Bianca Charlotin
Bianca Charlotin

Posted on

useParams and Dynamic Routes

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>
      );
    }


Enter fullscreen mode Exit fullscreen mode

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>
)
}

Enter fullscreen mode Exit fullscreen mode

Let look at each route

  1. <Route path="/" element={<ProjectDisplay />} /> . I have declared this URL structure: "projects/". renders all my projects.

  2. <Route path="new" element={<ProjectInput />} /> I have declared this URL structure: "projects/new", renders my project form for new project creation.

Dynamic Routes:

  1. <Route path=":id/edit" element={<ProjectUpdate />} />

  2. <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.

Image description

Below is my <ProjectDisplay /> code:


export default function ProjectDisplay() {

return(
 <div>
  {projects.map(p => {
   <Link to={`/projects/${p.id}/tasks`}>{p.title}
    </Link> 

 })}
 </div>
)}

Enter fullscreen mode Exit fullscreen mode

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:

  1. 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(
 )
...
}
Enter fullscreen mode Exit fullscreen mode
  1. const { id } = useParams(): Declared a variable using the destructured value of useParmas. { id } is the name I gave my dynamic route `.

  2. const useParamsProjectId = parseInt(id): Declared a variable which returns id that has been converted into an integer to use to compare later.

  3. const allTasks = useSelector(state => state.tasks): Here I am Grabbing all tasks from state (independent of the project) and setting it equal to a variable called alltasks

  4. const projectTasks = allTasks.filter((task) => (task.project_id === useParamsProjectId)): I'm using the method filter() to return a new array with all tasks that's project_id matches the useParams id aka useParamsProjectId and setting it equal to a variable called projectTasks.

There you have it useParams in full circle !

Top comments (0)