Sławomir Kwiatkowski

by: Sławomir Kwiatkowski

2024/12/01

Fetching a single record from an API using React

Content description:
In this post I'll describe how to get a single warehouse record.
The API is written in Django Rest Framework.
I will use dataLoader to get data from API.

The Warehouse() function uses the loader to obtain data about a specific warehouse. When the loader returns null, the login component is displayed.

     
import { useEffect } from "react"
import { useLoaderData, useNavigate, useLocation } from "react-router-dom"

function Warehouse() {
  
  const warehouse = useLoaderData()
  const navigate = useNavigate()
  const location = useLocation()
  
  useEffect(() => {
    if (warehouse===null) {
      navigate('/login', {state: {"from": location.pathname}})
    }
  },[]
  )

  return (
      <>
        {warehouse && 
          <><h1>{warehouse.warehouse_name}</h1>
            <h3>{warehouse.warehouse_info}</h3></>}
      </>
    )
}

The loader function is similar to the function that returns all warehouses belonging to a user:

     
const warehouseLoader = async ({params}) => {

  try {
    const token = localStorage.getItem('accessToken')
    const res = await fetch(`/api/warehouses/${params.id}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${token}`
      }
    })
    if (res.status==401) {
      const token = localStorage.getItem('refreshToken')
      const res = await fetch('/api/token/refresh/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({"refresh": token})
      })
      if (res.ok) {
        const data = await res.json()
        localStorage.setItem("accessToken", data["access"])
        warehouseLoader()
      } else {
        return null
      }
    }
    const data = await res.json()
    return data
  } catch (err) {
    console.log("error:", err)
  }
}
export {Warehouse as default, warehouseLoader}

All that's left is to add the URL to the router.

     
import WarehousePage from "./pages/WarehousePage"
import { warehouseLoader } from "./components/Warehouse"

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<MainLayout/>}>
      <Route index element={<MainPage/>} />
      <Route path="/warehouses" element={<WarehousesPage/>} />
      <Route path="/warehouses/:id" element={<WarehousePage/>} loader={warehouseLoader} />
      <Route path="*" element={<ErrorPage/>} />
    </Route>
  )
)