ChatGPT解决这个技术问题 Extra ChatGPT

Active link with React-Router?

I'm trying out React-Router (v4) and I'm having issues starting off the Nav to have one of the Link's be active. If I click on any of the Link tags, then the active stuff starts working. However, I'd like for Home Link to be active as soon as the app starts since that is the component that loads at the / route. Is there any way to do this?

Here is my current code:

const Router = () => (
  <BrowserRouter>
    <div>
      <Nav>
        <Link activeClassName='is-active' to='/'>Home</Link> {/* I want this to start off as active */}
        <Link activeClassName='is-active' to='/about'>About</Link>
      </Nav>

      <Match pattern='/' exactly component={Home} />
      <Match pattern='/about' exactly component={About} />
      <Miss component={NoMatch} />
    </div>
  </BrowserRouter>
)

K
Konrad Pettersson

This is an old, outdated answer for React Router v4

<Link> no longer has the activeClassName or activeStyle properties. In react-router v4 you have to use <NavLink> if you want to do conditional styling:

const Router = () => (
  <BrowserRouter>
    <div>
      <Nav>
        <NavLink exact activeClassName='is-active' to='/'>Home</NavLink>
        <NavLink activeClassName='is-active' to='/about'>About</NavLink>
      </Nav>

      <Match pattern='/' exactly component={Home} />
      <Match pattern='/about' exactly component={About} />
      <Miss component={NoMatch} />
    </div>
  </BrowserRouter>
)

I added an exact property to the home <NavLink>, I'm fairly sure that without it, the home link would always be active since / would match /about and any other pages you have.


I overlooked this answer today because I thought using NavLink was avoiding the problem at first glance. It is hard to find anywhere else that explains this. People need to upvote this answer because he is exactly right. you have to use NavLink. ALSO! the exact={true} is exactly right too. Otherwise the first link that renders will not re render when you click other links causing home to always be active. I wish I could upvote you 10 more times.
In case of nested routes, you might need to use exact for the NavLink too.
Thank you for that link, @PetrAdam - was wondering why this wasn't working! (the solution is to wrap the connect call with withRouter).
To avoid redux blocking a re-render you can provide the option pure: false to the connect() method. More information about a view no being updated: https://github.com/reduxjs/react-redux/blob/master/docs/troubleshooting.md
exact={true} on the home NavLink is a must, otherwise dashboard always stays active, very good explanation
C
Chilaxathor

React Router v6:

Source: Active NavLink Classes with React Router

Now you can use the className property which now accepts a function and passes an isActive boolean property, like this:

<NavLink
  to="users"
  className={({ isActive }) => (isActive ? 'active' : 'inactive')}
>
  Users
</NavLink>

You can also adding multiple classes too, since v6 is out:

<NavLink
  to="users"
  className={({ isActive }) =>
    isActive ? 'bg-green-500 font-bold' : 'bg-red-500 font-thin'
  }
>
  Users
</NavLink>

Live demo: Active NavLink Classes with React Router


L
Live Software Developer
import { NavLink, useMatch, useResolvedPath } from 'react-router-dom';

const CustomNavLink = ({ to, title }) => {
   let resolved = useResolvedPath(to);
   let match = useMatch({ path: resolved.pathname, end: true });

   return (
      <NavLink to={to} className={`d-flex align-items-center py-2 px-4 ${match ? 'cta-btn' : 'c-n-b-link'}`} >
        <span className='ms-1 f-w-600'>{title}</span>
      </NavLink>
)
}

For React router V6The above custom component will return a navlink that an active class can be activated whenever the path matches the given to path.


Thank you for this answer! This component can also be used to resolve the "deep nested active" link problem :)
Have just realized Navlink has an active class .active so if you pass in your own class like mynavlinkclass and target mynavlinkclass.active you can style the link when its active. This is Navlink from React router dom V6
N
Nima

In my case <NavLink /> automatically set active class to items so I use the following method

myComponet.js

<ListItem component={NavLink} to="/somewhere" className="myactive" > something </ListItem>

myStyle.css

a.active.myactive {
 // some styles
}

e
eneski

As an addition to @Nick's answer (React Router v6), for those who needs the active navigation state in the upper context..

Conditional rendering might be a use case for the need. For ex: if it is active render the filled icon otherwise render the regular one.

This could be achieved by finding the route that we are currently in and then we can do the conditional rendering operation however it would be a little cumbersome.

Instead, we can write a function that modifies the state in Navlink's style prop as following..

  const [active, setActive] = useState('home')

  const activate = (isActive, path, activeStyle, nonActiveStyle) => {
    if (isActive) {
      setActive(path)
      return activeStyle
    }
    return nonActiveStyle
  }

  return (
    <nav>
      <NavLink
        to="/"
        style={(activeNav) => activate(activeNav.isActive, 'home')}
      >
        {active === 'home' ? <HomeFill /> : <Home />}
      </NavLink>
      <NavLink
        to="/profile"
        style={(activeNav) => activate(activeNav.isActive, 'profile')}
      >
        {active === 'profile' ? <ProfileFilled /> : <Profile />}
      </NavLink>
    </nav>
  )

I respect that you want to enhance this but the code you provided has no explanation and does not really work. This would leave someone searching for an answer at an unwanted state. Maybe there is a way to improve your answer?
K
KARTHIKEYAN.A

In react-router-dom Version 5.3.0 I have used the following to enable the active link

classes:

active: {
        // background: 'linear-gradient(180deg, #008b32 0%, #cddc39 100%)',
        // backgroundColor: 'slategray',
        borderBottom: '1px solid white',
        borderRadius: '6px',
        boxShadow: 'rgba(6, 24, 44, 0.4) 0px 0px 0px 2px , rgba(6, 24, 44, 0.65) 0px 4px 6px -1px , rgba(255, 255, 255, 0.08) 0px 1px 0px inset',
        color: 'white',
        fontSize: '14px',
        listStyle: 'none',
        marginLeft: '16px',
        padding: '5px',
        textDecoration: 'none',
        textTransform: 'uppercase',
        transition: 'all 0.1s cubic-bezier(0.42, 0.02, 0.06, 0.05) 0.1s',
    },
    link: {
        '&:hover': {
            borderBottom: '1px solid white',
            borderRadius: '6px',
            boxShadow: 'rgba(6, 24, 44, 0.4) 0px 0px 0px 2px , rgba(6, 24, 44, 0.65) 0px 4px 6px -1px , rgba(255, 255, 255, 0.08) 0px 1px 0px inset',
            color: 'white',
            padding: '5px',
            transition: 'all 0.1s cubic-bezier(0.42, 0.02, 0.06, 0.05) 0.1s',
        },
        color: '#ddf1f9',
        fontSize: '14px',
        listStyle: 'none',
        marginLeft: '16px',
        textDecoration: 'none',
        textTransform: 'uppercase'
    },

NavLink.js

import React from "react";
import { useLocation } from "react-router-dom";


const NavLinks = classes => {
    const pathname = useLocation().pathname
    return (
        <nav>
            <ul className={classes.navlinks}>
                <li>
                    <Link
                        className={`${pathname === '/' ? classes.active : classes.link}`}
                        to='/'
                    >
                        Login
                    </Link>
                </li>
                <li>
                    <Link
                        className={`${pathname === '/dashboard' ? classes.active : classes.link}`}
                        to='/dashboard'
                    >
                        Dashboard
                    </Link>
                </li>
            </ul>
        </nav>
    )
}