SO react-router-bootstrap活动链接无法正常工作

时间:2018-06-18 19:16:42

标签: reactjs navigation react-router react-bootstrap react-router-bootstrap

我使用 react-router-bootstrap https://www.npmjs.com/package/react-router-bootstrap)组件时遇到活动链接问题。当我导航到关于时,活动类不仅会出现在关于上,还会出现在主页中。

Active Link react-router's issue

来自 react-bootstrap https://react-bootstrap.github.io/)的导航组件:

NavLinks.jsx

import React, { Component } from 'react';
import { Nav, NavItem } from 'react-bootstrap';

import HashNavItem from '../../Navigation/HashNavItem';

// import Flags from './Flags/Flags'
import "./NavLinks.css";

const routes = [{
  name: 'Home',
  path: '/',
  external: false
},{
  name: 'About',
  path: '/about',
  external: false
}, {
  name: 'Stores',
  path: '/#stores',
  external: false
}, {
  name: 'My Account',
  path: 'http://my-react.appicar.com/',
  external: true
}, {
  name: 'Services',
  path: '/#services',
  external: false
}, {
  name: 'Reviews',
  path: '/#reviews',
  external: false
}, {
  name: 'Contact',
  path: '/#contact',
  external: false
}];

export default class MainNav extends Component {

  handleClick(e) {
    e.preventDefault();
    alert('hola');
  }
  render() {
    let template;

    return (
      <Nav>
        {
          routes.map((route, key) => {
            if (route.external) {
              template = (
                <NavItem eventKey={ 'nav-' + key } href={ route.path } key={ key }>
                  {route.name}
                </NavItem>
              );
            } else {
              template = <HashNavItem eventKey={ 'nav-' + key } name={ route.name } to={ route.path } key={ key } />;
            }
            return template;
          })
        }
      </Nav>
    );
  }
}

HashNavItem.jsx

import React, { Component } from "react";
import { NavItem } from 'react-bootstrap';
import { LinkContainer } from "react-router-bootstrap";

export default class HashNavItem extends Component {

  constructor(props) {
    super(props);
    // Atributes.
    this.hashFragment = '';
    this.observer = null;
    this.asyncTimerId = null;
    this.scrollFunction = null;
    // States.
    this.state = {
      key: props.eventKey,
      name: props.name,
      to: props.to
    }
    // Methods.
    this.reset = this.reset.bind(this);
    this.getElAndScroll = this.getElAndScroll.bind(this);
    this.hashLinkScroll = this.hashLinkScroll.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }

  reset() {
    this.hashFragment = '';
    if (this.observer !== null) this.observer.disconnect();
    if (this.asyncTimerId !== null) {
      window.clearTimeout(this.asyncTimerId);
      this.asyncTimerId = null;
    }
  }

  getElAndScroll() {
    const element = document.getElementById(this.hashFragment);
    if (element !== null) {
      this.scrollFunction(element);
      this.reset();
      return true;
    }
    return false;
  }

  hashLinkScroll() {
    // Push onto callback queue so it runs after the DOM is updated
    window.setTimeout(() => {
      if (this.getElAndScroll() === false) {
        if (this.observer === null) {
          this.observer = new MutationObserver(this.getElAndScroll);
        }
        this.observer.observe(document, {
          attributes: true,
          childList: true,
          subtree: true,
        });
        // if the element doesn't show up in 10 seconds, stop checking
        this.asyncTimerId = window.setTimeout(() => {
          this.reset();
        }, 10000);
      }
    }, 0);
  }

  handleClick(e) {
    this.reset();
    if (this.props.onClick) this.props.onClick(e);
    if (typeof this.props.to === 'string') {
      this.hashFragment = this.props.to
        .split('#')
        .slice(1)
        .join('#');
    } else if (
      typeof this.props.to === 'object' &&
      typeof this.props.to.hash === 'string'
    ) {
      this.hashFragment = this.props.to.hash.replace('#', '');
    }
    if (this.hashFragment !== '') {
      this.scrollFunction =
        this.props.scroll || (el =>
          el.scrollIntoView(this.props.smooth ? { behavior: 'smooth' } : undefined)
        );
      this.hashLinkScroll();
    }
  }

  render() {
    return (
      <LinkContainer to={ this.state.to }>
        <NavItem eventKey={ this.state.key } key={ this.state.key } onClick={ this.handleClick }>{ this.state.name } </NavItem>
      </LinkContainer>
    );
  }
}

App.jsx

import React, { Component } from "react";
import { Router, Switch, Route } from 'react-router-dom';
import { createBrowserHistory } from 'history';

import MainNav from './MainNav/MainNav';
import Logo from './Logo/Logo';
import Footer from './Footer/Footer';
import Copyright from './Copyright/Copyright';
import HomePage from './HomePage/HomePage';
import AboutPage from './AboutPage/AboutPage';
import Error404 from './Error404/Error404';

import './App.css';

class App extends Component {
  render() {
    return (
      <Router history={ createBrowserHistory() }>
        <div>
          <MainNav />
          <Logo />
          <Switch>
            <Route exact path="/" component={ HomePage } />
            <Route exact path="/about" component={ AboutPage } />
            <Route exact path="/404" component={ Error404 } />
          </Switch>
          <Footer />
          <Copyright />
        </div>
      </Router>
    );
  }
}

export default App;

有谁知道为什么 主页 始终标记为有效

3 个答案:

答案 0 :(得分:1)

由于您已经使用了react-bootstrap软件包,因此可以像这样解决您的问题:

import { NavLink } from "react-router-dom";
import { Nav } from "react-bootstrap";
    
<Nav>
    <Nav.Link as={NavLink} exact to="/">
        Home
    </Nav.Link>
    <Nav.Link as={NavLink} exact to="/about">
        About
    </Nav.Link>
</Nav>

这里的关键是将exact属性与Nav.Link组件一起使用,并将as属性设置为NavLink,如上面的代码片段所示。

Check the documentation of the NavLink's exact property了解更多信息。

答案 1 :(得分:0)

我认为它与你的路线有关(所以react-router不一定是react-router-bootstrap)。我看到你在路线声明中加上'确切'但我会尝试在你的声明中添加'严格'。在我正在开发的应用程序中,我必须这样做才能使我的高阶组件验证包装器正常工作。

如果这不起作用那么我的猜测就是你如何迭代routes数组来动态创建nav-links。可能存在一个问题,即通过构建导航链接的方式清除活动状态。对不起,我没有更具体的答案!我还没有获得50+的声誉才能发表评论,所以希望有用的答案必须要做。

答案 2 :(得分:0)

您应该使用 IndexLinkContainer 而不是 LinkContainer

Check here