useParams and Dynamic Routes 
Published: 2021-12-09 23:17:52


##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 

```javascript
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:

```javascript
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 

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:

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

4. `<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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gp11si5fqnxqlt66zo4q.png)


Below is my `<ProjectDisplay />` code:

```javascript

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:
1. I need to know what project URL im on,  and find that projects task 

```javascript
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(
 )
...
}
```

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 !