Understanding and implementing useParams in React Routing

JOHN MURIITHIJOHN MURIITHI
5 min read

I recently interacted with the usePrams hook in a web application I was working on. I had seen it on a react routing tutorial by NetNinja UK and decided to use it on the web application I was working on. I used the useParams hook to display individual career details on the career section of the web application.

A list of available careers

Details about individual careers

I find it a very useful React Router hook in that it enables you to give details about individual items in a given list, for example in the case of listing products or services offered by a company or any other business. This article is a summary of my interaction with the useParams hook and how I employed it on this particular project, let's dive right into it!

What is useParams?

React Router is a powerful tool for creating single-page applications with dynamic, client-side routing. One of its most useful hooks is useParams, which allows you to access dynamic parameters in the URL.

useParams is a hook provided by React Router that enables you to extract parameters from the current URL. In other words, it allows you to have access to dynamic parameters in the URL(Uniform Resource Locator).

This is particularly useful for building dynamic and interactive web applications where components need to respond to changes in the URL.

How to use use useParams

Set up React Router

Before using useParams, you'll need to set up React Router in your application. This typically involves installing the package and configuring your routes.

Install react-router-dom :

npm install react-router-dom

For my project, I used version 6.4 of react-router-dom :

npm install react-router-dom@6.4

After installing react-router-dom we then go ahead to import createBrowserRouter,Route, createRoutesFromElements and RouterProvider from react-router-dom on the App.jsx file for configuring the routes to various parts of the web application, for example, the Career section in my case : http://localhost:5173/careers

import {
  createBrowserRouter,
  Route, 
  createRoutesFromElements,
  RouterProvider
} from 'react-router-dom'

Here is my configuration for the Careers route :

{/*careers parent route */}
      <Route path='careers' element = {<CareersLayout/>}    errorElement = {<CareersError />}>
        <Route
          index
          element = {<Careers />}
          loader={careersLoader}
          />
      {/*career details route with parameter id */}
      <Route                    
        path = ':id'    
        element = {<Careerdetails/>}
        loader = {careerDetailsLoader}
      /> 
      </Route>

I have two routes defined: one for the Careers page (/careers) and one for the Career details page (/careers/1 or /careers/2 and so on ). The :id in path = ':id' is a parameter that will be extracted using useParams.

id is an object of useParams and must therefore match with that of the parameter name specified in the path string of the route definition(the Careers parent route configuration above) which in this case is :id else you will encounter an error. You can name the parameter anything you want, but it is ideal to match it with one of the key in your data object so there’s no confusion.

using useParams in a Component

I have structured my App component by declaring an array of objects that holds the career details data. The array is on a json file that is being hosted on a json-server.

{
    "careers": [
      {
        "id": 1,
        "title": "Senior React Developer",
        "salary": 50000,
        "location": "Nairobi, Kenya"
      },
      {
        "id": 2,
        "title": "Plumber",
        "salary": 40000,
        "location": "Mombasa"
      },
      {
        "id": 3,
        "title": "Gym Leader",
        "salary": 75000,
        "location": "Nakuru"
      },
      {
        "id": 4,
        "title": "Vue Developer",
        "salary": 40000,
        "location": "Lagos, Nigeria"
      },
      {
        "id": 5,
        "title": "Tutorial Maker",
        "salary": 35000,
        "location": "Kigali, Rwanda"
      },
      {
        "id": 6,
        "title": "Website Manager",
        "salary": 50000,
        "location": "Berlin, Germany"
      },
      {
        "id": 7,
        "title": "Food Tester",
        "salary": 30000,
        "location": "London, UK"
      }
    ]
  }

I employed the useParams hook in the Careerdetails component :

// Careerdetails.jsx
import {  useLoaderData, useParams } from "react-router-dom"

export default function Careerdetails() {
    // eslint-disable-next-line no-unused-vars
    const { id } = useParams()     //used to access the route parameter id
    const career = useLoaderData()

  return (
    <div className='mt-4 p-8 m-12 shadow-2xl'>
        <h2 className='m-2'>Career details for <span className='text-teal-700'>{career.title}</span></h2>
        <p className='m-2'>Starting salary: {career.salary}</p>
        <p className='m-2'>Location: {career.location}</p>
        <div className='pt-4'>
            <p className='text-3xl text-teal-700'>Details for the above career</p>
        </div>
    </div>
  )
}
//career details loader: fetch details of a single career
// eslint-disable-next-line react-refresh/only-export-components
export const careerDetailsLoader = async ({ params }) => {
    const { id } = params

    const res = await fetch('http://localhost:4000/careers/' + id)

    if (!res.ok) {
        throw Error('Could not find that career')
    }

    return res.json()
}

In the above component (Careerdrtails.jsx), we import useParams from react-router-dom and call it within the component. This returns an object containing the parameters specified in the route (in this case, just id).

Fetching data from the json-server :

const res = await fetch('http://localhost:4000/careers/' + id)

We then create a component that will utilize useParams to access the id.

The Careers.jsx file in my case (/careers page) :

import { useLoaderData, Link } from "react-router-dom"


export default function Careers() {
  const careers = useLoaderData()


  return (
    <div className=''>
        {careers.map(career => (
          <Link className='hover:text-teal-700'  to = {career.id.toString()} key={career.id}>
            <div className='p-8 m-12 shadow-2xl'>
              <p className=''>{career.title}</p>
              <p className=''>Based in {career.location}</p>
              <div>
                <p>
                  Lorem ipsum
                </p>
              </div>
            </div>
          </Link>
        ))}
    </div>
  )
}

//careers loader function
// eslint-disable-next-line react-refresh/only-export-components
export const careersLoader = async () => {
  const res = await fetch('http://localhost:4000/careers')

  if (!res.ok) {
    throw Error('Could not fetch the careers')
}
  return res.json()
}

Link is an element that lets the user navigate to another page by clicking on it.

Now we destructure that data to have access to it and mapping its content in a div element with a class of Careerdetails.

/careers page showing the list of available careers

And here's how the careerdetails page came out, on clicking the individual careers on the careers page :

I used the useRouteError hook to get rid of errors that may arise when one enters an invalid URL on the Careers route.

Conclusion

useParams is a powerful tool provided by React Router for accessing dynamic parameters from the URL. It enables the creation of dynamic and interactive web applications by allowing components to respond to changes in the URL. By following the steps outlined above, you can effectively utilize useParams in your React applications. Happy coding!

1
Subscribe to my newsletter

Read articles from JOHN MURIITHI directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

JOHN MURIITHI
JOHN MURIITHI

I've been coding for three years. While being a developer is a difficult tug-of-war between my inner dreamer and critic, I've grown to love this process a lot. It hasn't just taught me much about the world, but also about myself.