Reputation: 51
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
What is the right method?
Upvotes: 2
Views: 2053
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
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>
))}
</>
);
};
Upvotes: 1
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
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