Home > database >  How to implement a nested route with a dynamic route?
How to implement a nested route with a dynamic route?

Time:09-07

All pages are being rendered in localhost/1, localhost/2, localhost/3, etc.

After the user select a card to show details, the url changes to localhost/info/:id, this id is the id from an array.

The page with the card details let's say is localhost/info/1, everything look good. The problem is that inside of this page there is another link to be clicked.

If this bottom is clicked, the url should change to localhost/info/1/episodes and this new component should be rendered with the others details from the card.

How can I correctly implement this feature to render two components together? I'm still learning React Router.

All Routes.tsx

import Home from "../pages/Home";
import CharacterInfo from "../pages/CharacterInfo";
import { Route, Routes, Navigate } from "react-router-dom";
import Episodes from "../pages/Episodes";

const AllRoutes = () => {
  return (
    <Routes>
      <Route path="/" element={<Navigate to="/1" />} />
      <Route path="/info">
        <Route path=":id" element={<CharacterInfo />}>
          <Route path="/info/:id/episodes" element={<Episodes />} />
        </Route>
      </Route>
      <Route path="/:p" element={<Home />} />
      <Route path="*" element={<Home />} />
    </Routes>
  );
};

export default AllRoutes;

CharacterInfo.tsx

import { useContext, useEffect } from "react";
import { useParams, Routes, Route, Link, useNavigate } from "react-router-dom";
import { GetACharacterContext } from "../contexts/GetACharacterContext";
import Episodes from "./Episodes";

const CharacterInfo = () => {
  const { characterDetail, setId } = useContext(GetACharacterContext);
  const { id } = useParams();
  const navigate = useNavigate();

  useEffect(() => {
    setId(Number(id));
  }, [id]);

  return (
    <>
      <button onClick={() => navigate("/1")}>Home</button>
      <p>{characterDetail.id}</p>
      <p>{characterDetail.name}</p>
      <p>{characterDetail.age ? characterDetail.age : "No data"}</p>
      <p>{characterDetail.occupation}</p>
      <Link to={`/info/${characterDetail.id}/episodes`}>Episodes</Link>
    </>
  );
};

export default CharacterInfo;

Episodes.tsx

const Episodes = () => {
  return <div>Episodes</div>;
};

export default Episodes;

CodePudding user response:

CharacterInfo needs to render an Outlet component for the nested routes it's rendering, and the path needs to be relative from the parent route.

Example:

const AllRoutes = () => {
  return (
    <Routes>
      <Route path="/" element={<Navigate to="/1" />} />
      <Route path="/info">                                 // "/info"
        <Route path=":id" element={<CharacterInfo />}>     // "/info/:id"
          <Route path="episodes" element={<Episodes />} /> // "/info/:id/episodes"
        </Route>
      </Route>
      <Route path="/:p" element={<Home />} />
      <Route path="*" element={<Home />} />
    </Routes>
  );
};

...

const CharacterInfo = () => {
  const { characterDetail, setId } = useContext(GetACharacterContext);
  const { id } = useParams();
  const navigate = useNavigate();

  useEffect(() => {
    setId(Number(id));
  }, [id]);

  return (
    <>
      <button onClick={() => navigate("/1")}>Home</button>
      <p>{characterDetail.id}</p>
      <p>{characterDetail.name}</p>
      <p>{characterDetail.age ? characterDetail.age : "No data"}</p>
      <p>{characterDetail.occupation}</p>
      <Link to={`/info/${characterDetail.id}/episodes`}>Episodes</Link>
      <Outlet /> // <-- nested routes render content here
    </>
  );
};

CodePudding user response:

You can try it like this:

<Routes>
  <Route path="/" element={<Navigate to="/1" />} />
  <Route path="/info/:id" element={<CharacterInfo />} />
  <Route path="/info/:id/episodes" element={<Episodes />} />
</Routes>  
  • Related