【问题标题】:What is the correct way to track which item is active in a tree, in react在反应中跟踪树中哪个项目处于活动状态的正确方法是什么
【发布时间】:2021-08-30 02:38:25
【问题描述】:

我使用Carbon's SideNav 组件作为页面的树形导航控件。叶子可以通过isActive 布尔属性或添加aria-current='page' 来设置active。如果叶子在子菜单中,则在其任何子菜单处于活动状态时扩展菜单。活动项目跟踪不是开箱即用的,它必须添加。我有两个问题:

  1. 实施活动项目跟踪的正确方法是什么?我可以想到两种方法:向每个 SideNavMenuItem 添加一个 onClick() 或者,正如我目前实现的那样:将一个引用数组放在一起,然后使用 useEffect() 从所有类中删除活动类并将其添加到被选中
  2. 当包含组件安装时(例如,在页面刷新或通过书签导航到页面)时,标记活动项目的正确方法是什么。我的参考代码通过将所需的类添加到菜单项来设置活动状态,但 SideNavMenu 只有在其任何子项处于活动状态时才会打开 - 这是我无法通过参考设置的属性。

我当前的示例基于一个小型的 8 项树,但我必须将其扩展到更大的规模。

const MySidebar = () => {

  const menuRefs = useRef(new Array());

  useEffect(() => {
    const className = "bx--side-nav__link--current";
    menuRefs.current.forEach(ref => {ref.classList.remove(className)})
    const ref = menuRefs.current.filter((ref) => ref.baseURI === ref.href);
    if (ref) {
      ref[0].classList.add(className);
    }
  });

  return (
      <SideNav
      className="my-nav"
      isFixedNav
      expanded={true}
      isChildOfHeader={false}
      aria-label="Side navigation"
      >
        <SideNavItems>
          <SideNavMenuItem ref={(element) => menuRefs.current[0] = element} element={Link} to="page1">Page 1</SideNavMenuItem>
          <SideNavMenuItem ref={(element) => menuRefs.current[1] = element} element={Link} to="page2">Page 2</SideNavMenuItem>
          <SideNavMenu  title='Some submenu'>
            <SideNavMenuItem ref={(element) => menuRefs.current[2] = element} element={Link} to="page3">Page 3</SideNavMenuItem>
            <SideNavMenuItem ref={(element) => menuRefs.current[3] = element} element={Link} to="page4">Page 4</SideNavMenuItem>
            <SideNavMenuItem ref={(element) => menuRefs.current[4] = element} element={Link} to="page5">Page 5</SideNavMenuItem>
            <SideNavMenuItem ref={(element) => menuRefs.current[5] = element} element={Link} to="page6">Page 6</SideNavMenuItem>
            <SideNavMenuItem ref={(element) => menuRefs.current[6] = element} element={Link} to="page7">Page 7</SideNavMenuItem>
          </SideNavMenu>
          <SideNavMenuItem ref={(element) => menuRefs.current[7] = element} element={Link} to="page8">Page 8</SideNavMenuItem>
        </SideNavItems>
      </SideNav>
  );
};

【问题讨论】:

    标签: javascript reactjs carbon-design-system


    【解决方案1】:

    在内存中拥有活动项目不是要走的路,你应该从 url 推断它。您可以使用hashed routesroute parameters 来跟踪活动项目,单击后将其推送到 url,直接从组件中的 url 使用它。这样它就不会在刷新时丢失活动项目,并且网址也可以添加书签和共享。

    【讨论】:

    • 活动项目未保存在内存中。 URL 表示在每个项目加载特定页面时活动项目是哪一个。我很难弄清楚如何将 URL 链接到元素的 isActive 属性
    • @RekaB 你在使用ReactRouter 吗?因此,例如,如果您将活动项目推送到搜索参数,它将类似于http://localhost:300/home?page=page6,您可以从window.location.search 获取值,如果它在路径中,您将不得不进行一些字符串处理。如果您使用的是推荐的 react-router,它更容易,访问路径参数将是 match.params.{paramId}。搜索相同。
    • 问题不是确定页面是否处于活动状态,而是让 SideNav 元素意识到这一点。我现在已经通过使用NavLink 而不是Link 解决了这个问题,但我仍然需要能够打开 SideNavMenu。我还对调整可能动态生成的子对象的属性的一般最佳实践感兴趣
    • @RekaB 如果你能提供一个codesandbox.io 最小的例子,我可以帮忙。
    • 这不是跟踪活动页面吗?有什么问题?
    【解决方案2】:

    为了在用户使用内容 div 内的链接导航时打开树/跟踪项,我最终用我自己的组件包装了原始的 SideNavMenu,它递归地检查是否有任何孩子有指向当前位置的链接.我将检查分为三种方法,以避免在其中任何一种中出现if 语句的字段。我仍然不知道这是否是正确的方法,但它有效。

    class MySideNavMenu extends React.Component {
      hasActiveChild = (child) => {
        if (child.props.element) { // leaf
          return this.props.location.pathname === child.props.to;
        }
        if (child.props.children) { // node
          return this.checkChildren(child.props.children);
        }
      };
    
      checkChildren = (children) => {
        return Array.isArray(children)
          ? children.some((child) => {
              return this.hasActiveChild(child);
            })
          : this.hasActiveChild(children);
      };
    
      isExpanded = () => {
        const children = this.props.children;
        if (children) {
          // if we have children, either a single or multiple, find if it is active
          return this.checkChildren(children);
        }
    
        return false;
      };
    
      render() {
        return (
          <SideNavMenu defaultExpanded={this.isExpanded()} title={this.props.title}>
            {this.props.children}
          </SideNavMenu>
        );
      }
    }
    
    export default withRouter(MySideNavMenu);
    

    【讨论】:

      猜你喜欢
      • 2016-12-28
      • 1970-01-01
      • 2016-07-18
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-22
      • 2012-11-08
      相关资源
      最近更新 更多