web-dev-qa-db-fra.com

Comment définir activeClassName pour l'élément wrapper de Link ou IndexLink dans react-router?

Je suis nouveau dans le monde de ReactJS et voudrais savoir comment puis-je transmettre le nom de la classe active à l'élément <li> au lieu de l'élément <a>(Link).

Maintenant, j'ai ce genre de code. La classe d'ancrage change lorsque vous cliquez dessus.

<li><IndexLink to='/' activeclassName='active'>A</IndexLink></li>
<li><Link to='/b' activeclassName='active'>B</Link></li>
<li><Link to='/c' activeclassName='active'>C</Link></li>

Mais j'aimerais avoir quelque chose de similaire à:

<li activeclassName='active'><IndexLink to='/'>A</IndexLink></li>
<li activeclassName='active'><Link to='/b'>B</Link></li>
<li activeclassName='active'><Link to='/c'>C</Link></li>

Merci d'avance

42
abekenza

Vous devez inclure votre <li> en tant que composant sensible au routeur:

import { Link, IndexLink } from 'react-router'

class NavItem extends React.Component {
  render () {
    const { router } = this.context
    const { index, onlyActiveOnIndex, to, children, ...props } = this.props

    const isActive = router.isActive(to, onlyActiveOnIndex)
    const LinkComponent = index ? Link : IndexLink

    return (
      <li className={isActive ? 'active' : ''}>
        <LinkComponent {...props}>{children}</LinkComponent>
      </li>
    )
  }
}

Usage:

<ul>
  <NavItem to='/' index={true}>Home</NavItem>
  <NavItem to='/a'>A</NavItem>
</ul>

Je suis inscrit au module react-router-bootstrap, https://github.com/react-bootstrap/react-router-bootstrap/blob/master/src/LinkContainer.js . Je ne l'ai pas testé, alors laissez-moi savoir comment ça se passe.

37
Marc Greenstock

Les autres réponses ne semblent pas fonctionner dans React Router v4. Voici comment vous pouvez le faire:

import React, {PropTypes} from 'react'
import {Route, Link} from 'react-router-dom'
import styles from './styles.less';

export default function NavItem({children, to, exact}) {
    return (
        <Route path={to} exact={exact} children={({match}) => (
            <li className={match ? styles.activeRoute : null}>
                <Link to={to}>{children}</Link>
            </li>
        )}/>
    )
}

NavItem.propTypes = {
    to: PropTypes.string.isRequired,
    exact: PropTypes.bool,
    children: PropTypes.node.isRequired,
};
17
mpen
/**
 * A navigation component
 */
import React, { Component } from 'react'
import { Link, IndexLink, withRouter } from 'react-router'

import styles from './styles.scss'

class NavItem extends Component {
  render () {
    const { router } = this.props
    const { index, to, children, ...props } = this.props

    let isActive
    if( router.isActive('/',true) && index ) isActive = true
    else  isActive = router.isActive(to)
    const LinkComponent = index ?  IndexLink : Link

    return (
      <li className={isActive ? 'active' : ''}>
        <LinkComponent to={to} {...props}>{children}</LinkComponent>
      </li>
    )
  }
}

NavItem = withRouter(NavItem)

export default NavItem

Usage:

<ul className="nav nav-tabs"> 
  <NavItem to='/home' index={true} >Home</NavItem>
  <NavItem to='/about'>About</NavItem>
</ul>
10
bryanyu

Au lieu d'utiliser <Link />, j'utilise <NavLink /> et cela fonctionne aussi bien. 

import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';

//.....

export default class AppNav extends Component {

    render (){
        return (
                <header>
                    <ul className="main-nav">
                        <li><NavLink activeClassName={"active"} exact={true} to="/">Home</NavLink></li>
                        <li><NavLink activeClassName={"active"} to="/about">About</NavLink></li>
                        <li><NavLink activeClassName={"active"} to="/courses">Courses</NavLink></li>
                    </ul>
                </header>
        );
    }
}
6
Dimang Chou
{/* Make sure that `location` is injected into this component */}
<ul className="nav navbar-nav">
  <li className={location.pathname === '/' && 'active'}>
    <Link to='/'>
      Home page
    </Link>
  </li>
  <li className={location.pathname.startsWith('/about') && 'active'}>
    <Link to='/about'>
      About us
    </Link>
  </li>
</ul>
4
Ken Berkeley

Très bonne réponse.

Il suffit de changer ce qui suit pour le faire fonctionner ...

LinkComponent = index ? IndexLink : Link //If its true you want an IndexLink 

//Also link needs to be...
<NavItem to="/" onlyActiveOnIndex index={true}>Home</NavItem>
3
Matthew Berends

Essayez avec react-router-active-composant .

Aucune des réponses précédentes ne fonctionnait facilement en raison d'incompatibilités entre les versions de réaction et de TypeScript (il ne s'agit certainement pas d'un écosystème mature), mais ce composant a fait l'affaire et peut être appliqué à d'autres éléments que li si nécessaire:

import activeComponent from 'react-router-active-component'
let NavItem = activeComponent('li');
...
<NavItem to='/' onlyActiveOnIndex>Home</NavItem>
<NavItem to='/generate-keywords'>Generate keywords</NavItem>
1
Erwin Mayer

En utilisant react 15.1.0, react-router 2.5.0 et bootstrap 3.3 (c'est moins important), j'ai développé cette solution pour rendre les liens actifs:

npm install --save classnames

npm install --save lodash

Le composant:

import React from 'react';
import { Link, IndexLink } from 'react-router';
import _ from 'lodash';
import classnames from 'classnames';

class NavItem extends React.Component {
  constructor(props) {
    super(props);

    // The default state
    this.state = {
      isActive: false,
      unregisterRouteListener: false
    };

    // Binding for functions
    this.locationHasChanged = this.locationHasChanged.bind(this);
  }

  componentDidMount() {
    // Check if component is active on mount and add listener on route change
    this.setState({
      isActive: this.context.router.isActive(this.props.to, true),
      unregisterRouteListener: this.context.router.listen(this.locationHasChanged)
    });
  }

  componentWillUnmount() {
    if (this.state.unregisterRouteListener) {
      // Remove the listener
      this.state.unregisterRouteListener();
    }

    // Reset the state
    this.setState({
      isActive: false,
      unregisterRouteListener: false
    });
  }

  // Update the state of the component, based on the router path
  locationHasChanged() {
    this.setState({
      isActive: this.context.router.isActive(this.props.to, true)
    });
  }

  render () {
    let { index } = this.props;
    let LinkComponent = index ? Link : IndexLink;
    let newProps = _.omit(this.props, 'router');

    return (
      <li className={classnames('', this.state.isActive ? 'active' : '' )}>
        <LinkComponent {...newProps}>
          {this.props.children}
        </LinkComponent>
      </li>
    );
  }
}

NavItem.contextTypes = {
  router: React.PropTypes.object
};

export default NavItem;

Usage:

<NavItem to="/list">List</NavItem>

Je suis un débutant avec React, la solution ci-dessus a donc sûrement besoin d’être améliorée et peut contenir des erreurs d’approche. Cependant, il peut également contenir des informations utiles ou un point de départ pour les personnes intéressées. 

Tous les commentaires ou suggestions sont plus que bienvenus. Merci! :)

1
Cristi Draghici

En utilisant React Router v4, je l’ai seulement obtenu en incluant les balises <li> dans le composant NavLink. Les solutions dont les balises <li> encapsulent les liens ont pour résultat que la balise HOME <li> a toujours la classe active.

import React from 'react'
import { NavLink } from 'react-router-dom';

class Header extends React.Component {

  render() {
    return (
      <div>
        <header>

          <nav>
            <ul>
              <NavLink activeClassName={"active"} exact={true} to="/"><li>Home</li></NavLink>
              <NavLink activeClassName={"active"} to="/about"><li>About</li></NavLink>
              <NavLink activeClassName={"active"} to="/courses"><li>Courses</li></NavLink>
            </ul>
          </nav>

        </header>
      </div>
    )
  }
}

export default Header

J'ai ajusté les sélecteurs CSS li et a en conséquence.

0
Steve Breese

J'utilise React Router v4.2 et je n'ai pas pu obtenir la référence à l'objet routeur à partir du composant d'habillage, car le contexte n'est pas disponible.

Cela n'a pas fonctionné:

const { router } = this.context

J'aime @/mpen's answer , mais j'utilise des itinéraires imbriqués et je ne souhaite pas modifier le fichier dans lequel le composant de routage est défini.

Ce que j'ai fait est comparé le location.pathname avec à:

const NavItem = withRouter((props) => {
const { to, children, location } = props;
return (
    <li className={location.pathname == to ? 'active' : null}>
        <Link to={to}>{children}</Link >
    </li>
)});
0
Jernej Gorički