简体   繁体   中英

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>
)

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={true} 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.

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

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 V6 The above custom component will return a navlink that an active class can be activated whenever the path matches the given to path.

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
}

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>
  )

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>
    )
}

Inspired by @Live Software Developer, in v6, I believe it's much simpler to do this (the typing below comes from TypeScript):

const CustomNavLink: React.FC<{ to: string; text: string }> = ({
  to,
  text,
}) => {
  return (
    <NavLink
      to={to}
      className={({ isActive }) => (isActive ? "active" : "inactive")}
    >
      {text}
    </NavLink>
  );
};

React 路由器文档对此有所帮助: https : //reactrouter.com/web/api/NavLink您可以指定确切的链接并设置活动链接的样式

I know I'm kind of late to the party, but I handle this by setting an inline style :focus {whatever your styles are} I handle most styling inline, but I'm pretty sure this will work in a regular stylesheet too. just use

:focus

instead of

:active

EDIT

I, for a few reasons (mostly embedded software), can't use css style sheets. So I've grown to love inline styling (contrary to opinion, inline styles have worked well for a project with about 8000 lines of code spanning 37 files, with no performance impact). But unfortunately, the :active selector is bugged when using it inline like this, so I use the above method.

Another way to do this, because I know inline styles are kind of frowned upon, is to make a css active class with the styles you'd like for the nav-element, and keep a state variable to track your current page as high up in scope as your comfortable with (preferably root component), and update it when user navigates to another page. This can be done by wrapping <Redirect/> or <Link to={}/> with a functional component that handles updating state and navigation, and in your navigation component, check if the nav-element your rendering matches the current page, and if so, append your active css class to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM