将React路由器活动NavLink与子组件集成

时间:2018-04-22 04:26:45

标签: reactjs react-router

我的菜单目前看起来像这样:

<Menu>
    <MenuItem text="link1" />
    <MenuItem text="link2" />
</Menu>

为了与react-router-dom集成,我按以下方式进行了修改:

<Menu>

    <NavLink to="link1">
        <MenuItem text="link1" />
    </NavLink>

    <NavLink to="link2">
        <MenuItem text="link2" />
    </NavLink>

</Menu>

我的MenuItem组件支持当前&#34;活动&#34;的样式化。如此链接:

<MenuItem active text="link1" />

如何整合&#34;活跃&#34;路由样式与react-router-dom

我可以通过以下方式设置一些布尔值吗?

<MenuItem active={isRouteActive} text="link1" />

编辑: MenuItem是Blueprintjs的一个组件。设置active道具后,可能会将一些内部样式规则应用于组件。我可以在activeClassName上使用NavLink道具,但我不想复制第三方组件的CSS。

5 个答案:

答案 0 :(得分:3)

不幸的是,来自rr4的NavLink目前还没有提供将<Route/>信息传递给其子级(MenuItem)的方法。

好的是rr4采用以组件为中心的方法,因此字面上一切都只是反应组件,NavLink本身就是一个由以下组成的自定义组件:

  • <Link/>(处理路线匹配)
  • const NavLink = ({ to, children, className, activeClassName, ...rest }) => { const path = typeof to === "object" ? to.pathname : to; return ( <Route path={path} children={({ match }) => { const isActive = !!match; return ( <Link {...rest} className={ isActive ? [className, activeClassName].filter(i => i).join(" ") : className } to={to} > {typeof children === 'function' ? children(isActive) : children} </Link> ); }} /> ); }; export default NavLink; (调度路线行动)

我们可以创建我们的自定义链接类型,如:

<Menu>
  <NavLink to="link1">
    {isActive => <MenuItem active={isActive} text="link1" />}
  </NavLink>
  <NavLink to="link2">
    {isActive => <MenuItem active={isActive} text="link2" />}
  </NavLink>
</Menu>

然后将其用作:

state = { activeLink: '' }
render() {
  return (
    <Menu>
      <Link to='link1' onClick={() => this.setState({ activeLink: 'link1' })>
        <MenuItem active={this.state.activeLink === 'link1'} text='link1' />
      </Link>
      <Link to='link2' onClick={() => this.setState({ activeLink: 'link2' })>
        <MenuItem active={this.state.activeLink === 'link2'} text='link2' />
      </Link>
    </Menu>
  )
}

这使用render props从父级到子级共享isActive状态。这应该可以正常工作,但要完全模仿Navr在rr4中工作的方式(例如,可访问性支持),可能仍然需要根据implementation修补它。

对于这种特定情况,使用本地状态w / Link可能更容易

{{1}}

答案 1 :(得分:3)

我最终搞清楚了。我使用Route组件

的组合创建了自己的组件
const MenuItemExt = ({ icon, text, to, activeOnlyWhenExact }) => {
  return (
    <Route
      path={to}
      exact={activeOnlyWhenExact}
      children={({match, history}) => (
        <MenuItem
          active={match}
          icon={icon}
          onClick={() => {
            history.push(to);
          }}
          text={text}
        />
      )}
    />
  );
};

答案 2 :(得分:1)

假设您有2条路线:

/ admin

/ admin /特权

您希望在打开上述链接中的任何一个时,导航栏文本“ Admin”为活动颜色。您可以通过以下方式实现此目标:

<NavLink
            exact
            to="/admin"
            className="..."
            activeClassName="..."
            isActive={(match, location) => {
              let pathStrings = location.pathname.split('/');

// pathstrings will be ['/', 'admin', '/', 'privileges']
// should you add a new subroute, say /admin/locations/ the code would still work


              if (match) {
                return true;
              } else if (pathStrings[1] === 'admin') {
                return true;
              } else {
                return false;
              }
            }}
          >
            Admin
          </NavLink>

答案 3 :(得分:0)

您可以使用来自反应路由器的道具activeClassName

<NavLink activeClassName="custom-active-class" to="link1">
    <MenuItem className="custom-link-class" text="link1" />
</NavLink>

<NavLink activeClassName="custom-active-class" to="link2">
    <MenuItem className="custom-link-class" text="link2" />
</NavLink>

并稍微改变你的css

.custom-active-class .custom-link-class{ background-color: red; }

答案 4 :(得分:0)

这是另一种方法;如果您正在遍历导航链接数组并需要动态检查;

// Routes
<Route exact path="/news" component={News} />
<Route path="/news/:nid" component={NewsDetails} />

{this.state.navItems.auth.map((item, index) => {
  return (
    <li key={index} className="nav-item">
      <NavLink
        exact
        to={item.path}
        className="nav-link"
        activeClassName="active"
        onClick={this.handleClick}
        isActive={(match, location) => {
          if (match) {
            return true;
          }

          if (location.pathname.indexOf(item.path) > -1) {
            // Prevent home from matching
            if (item.path !== '/') {
              return true;
            }
          }
        }}>
        ...
      </NavLink>
    </li>
  );
})}