将React Router主动NavLink与子组件集成

Kri*_*son 3 reactjs react-router

我的菜单当前如下所示:

<Menu>
    <MenuItem text="link1" />
    <MenuItem text="link2" />
</Menu>
Run Code Online (Sandbox Code Playgroud)

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

<Menu>

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

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

</Menu>
Run Code Online (Sandbox Code Playgroud)

我的MenuItem组件支持当前“活动”链接的样式,如下所示:

<MenuItem active text="link1" />
Run Code Online (Sandbox Code Playgroud)

如何整合“主动”路线样式react-router-dom

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

<MenuItem active={isRouteActive} text="link1" />
Run Code Online (Sandbox Code Playgroud)

编辑: MenuItem是Blueprintjs的一个组件。当active支柱被设置时,其可能的一些内部造型规则被应用于该组件。我可以在上面使用该activeClassName道具,NavLink但我不想复制第3方组件的CSS。

Xle*_*lee 5

isActive不幸的是,rr4 的 NavLink目前不提供将信息传递给其子项(MenuItem)的方法。

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

  • <Route/>(处理路由匹配)
  • <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;
Run Code Online (Sandbox Code Playgroud)

然后将其用作:

<Menu>
  <NavLink to="link1">
    {isActive => <MenuItem active={isActive} text="link1" />}
  </NavLink>
  <NavLink to="link2">
    {isActive => <MenuItem active={isActive} text="link2" />}
  </NavLink>
</Menu>
Run Code Online (Sandbox Code Playgroud)

这使用渲染道具从父级到子级共享 isActive 状态。这应该可以正常工作,但为了完全模仿 NavLink 在 rr4 中的工作方式(例如,可访问性支持),可能仍然需要根据其实现对其进行修补。

对于这种特定情况,使用带有链接的本地状态可能会更容易

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>
  )
}
Run Code Online (Sandbox Code Playgroud)


Kri*_*son 5

我最终弄清楚了。我使用组件的组成创建了自己的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}
        />
      )}
    />
  );
};
Run Code Online (Sandbox Code Playgroud)