so_hell
so_hell

Reputation: 51

HIghlight Active Link in the Navbar , React

This is a simple version of the problem not the actual problem. React code:

<Router>
   <Navbar/>
   <Routes>
       <Route path="/:genreId" element={<MovieList/>} />
   <Routes>
<Router>

This problem is that in the Navbar, I have several button to go the particular genre. I want to highlight active button in the Navbar (when I click "comedy" the "comedy" button should be lit up)

some solutions

  1. State => will not work if I reload
  2. Session Storage => will not work if I come be website for the first time
  3. Extract the params using the useParams Hook => this will not work since param "genreId" is available to the movieList component not the navbar
  4. Extract from the window.location => Don't want to do it since it look too ad-hock

What is the right method?

Upvotes: 2

Views: 2053

Answers (4)

JimmyZ
JimmyZ

Reputation: 21

try useLocation hook in react-router-dom.

It's kind of similar the solution with "4.Extract from the window.location => Don't want to do it since it look too ad-hock",

by using this hook, it is not so "ad-hock".

import { Link, useLocation } from 'react-router-dom';
const currentPage = useLocation().pathname;

<Link 
  key={1} 
  className={currentPage === '/' ? 'nav-link active' : 'nav-link'} 
  to="/"
>

Upvotes: 2

Drew Reese
Drew Reese

Reputation: 203587

I would suggest #3 "Extract the params using the useParams Hook => this will not work since param "genreId" is available to the movieList component not the navbar". You are correct though, this doesn't work since the Navbar component is rendered outside the Routes component and won't have access to the currently matched route. To resolve this you should move the Navbar component inside the Routes component. To make this work you'll create a layout route component that renders the Navbar component and an Outlet component for nested routes to render their element prop into.

Example:

import { Outlet } from 'react-router-dom';

const Layout = () => (
  <>
    <Navbar />
    <Outlet />
  </>
);

Then render the MovieList route as a nested route of the layout route.

<Routes>
  <Route element={<Layout />}>
    <Route path="/:genreId" element={<MovieList />} />
  </Route>
</Routes>

The Navbar component can now safely access the genreId route path param and use it to apply any logic necessary to mark a button as "active. Here's a simple example:

const genres = ["action", "comedy", "drama"];

const Navbar = () => {
  const navigate = useNavigate();
  const { genreId } = useParams();

  const navigateTo = (genreId) =>
    navigate(generatePath("/:genreId", { genreId }));

  return (
    <>
      {genres.map((genre) => (
        <button
          key={genre}
          className={["genreButton", genreId === genre && "active"]
            .filter(Boolean)
            .join(" ")}
          type="button"
          onClick={() => navigateTo(genre)}
        >
          {genre}
        </button>
      ))}
    </>
  );
};

enter image description here

Edit highlight-active-link-in-the-navbar-react

Upvotes: 1

EMRAN HOSSAIN
EMRAN HOSSAIN

Reputation: 111

You can use NavLink instead of Link to design the active route. Here is the documentation.

    <Router>
       <Navbar/>
       <Routes>
           <Route path="/:genreId" element={<MovieList/>} />
       <Routes>
    <Router>

In the Navbar component you can write like this to have the active link:

   <nav>
      <NavLink to="/:genreId">Genre Name</NavLink>
   </nav>

Upvotes: 1

Nazmus Shakib
Nazmus Shakib

Reputation: 16

I usually use IndexDB for that kind of stuff. To manage the IndexDB perfectly you can use localforage. You can check this link.localforage

Upvotes: 0

Related Questions