useRef.current.contains 不是函数

Jia*_*827 5 sass reactjs material-ui

我在导航栏中有一个使用 material-ui/core 构建的导航菜单。

我使用 useRef 来跟踪切换菜单关闭时单击按钮的位置。 anchorRef.current.contains(event.target)

我得到'Uncaught TypeError: anchorRef.current.contains is not a function'.

我尝试了 'Object.values(anchorRef.current).includes(event.target)',它总是返回 false。

- 更新 -

anchorRef.current.props 对象。

withStyles {
    props:{
     aria-haspopup: "true"
     aria-owns: undefined
     children: "??"
     className: "nav-menu--btn"
     onClic: f onClick()
     get ref: f()
      isReactWarning: true
      arguments: (...)
      caller: (...)
      length: 0
      name: "warnAboutAccessingRef"
     ...
    }, context{...}, refs{...}, ...}
Run Code Online (Sandbox Code Playgroud)

切换菜单列表

const ToggleMenuList = ({ navAdminList, navAdminItems, classes }) => {
  const [activeId, setActiveId] = useState(null);
  const anchorRef = useRef(null);
  const handleToggle = id => {
    setActiveId(id);
  };
  const handleClose = event => {
    if (anchorRef.current && anchorRef.current.contains(event.target)) {
      return;
    }
    setActiveId(null);
  };

  return (
    <React.Fragment>
      <div className={`nav-menu--admin ${classes.root}`}>
        {navAdminList.map(e => (
          <div key={e.id}>
            <Button
              ref={anchorRef}
              aria-owns={activeId === e.id ? 'menu-list-grow' : undefined}
              aria-haspopup="true"
              onClick={() => handleToggle(e.id)}
            >
              {e.name}
            </Button>
            {activeId === e.id && (
              <ToggleMenuItems
                id={e.id}
                activeId={activeId}
                handleClose={handleClose}
                anchorRef={anchorRef}
                items={navAdminItems[e.id]}
              />
            )}
          </div>
        ))}
      </div>
    </React.Fragment>
  );
};

export default withStyles(styles)(ToggleMenuList);

Run Code Online (Sandbox Code Playgroud)

切换菜单项

 const ToggleMenuItems = ({
      listId,
      activeId,
      handleClose,
      anchorRef,
      items,
    }) => {
      const isOpen = activeId === listId;
      const leftSideMenu = activeId === 3 || activeId === 4 ? 'leftSideMenu' : '';
    
      return (
        <Popper
          open={isOpen}
          anchorEl={anchorRef.current}
          keepMounted
          transition
          disablePortal
        >
          {({ TransitionProps, placement }) => (
            <Grow
              {...TransitionProps}
              style={{
                transformOrigin:
                  placement === 'bottom' ? 'center top' : 'center bottom',
              }}
              className={`toggle-menu ${leftSideMenu}`}
            >
              <Paper id="menu-list-grow">
                <ClickAwayListener
                  onClickAway={handleClose}
                >
                  <MenuList className="toggle-menu--list">
                    {items.map(e => (
                      <MenuItem
                        key={e.id}
                        className="toggle-menu--item"
                        onClick={handleClose}
                      >
                        <Link
                          to={e.to}
                          className="anchor td-none c-text1 toggle-menu--link"
                        >
                          {e.name}
                        </Link>
                      </MenuItem>
                    ))}
                  </MenuList>
                </ClickAwayListener>
              </Paper>
            </Grow>
          )}
        </Popper>
      );
    };
    
    export default ToggleMenuItems;
Run Code Online (Sandbox Code Playgroud)
react: ^16.8.6
react-dom: ^16.8.6
react-router-dom: ^4.3.1
@material-ui/core: ^3.1.2
Run Code Online (Sandbox Code Playgroud)

sky*_*yer 1

我假设您在单击外部某处时ToggleMenuItems设置了全局(document-level?)事件侦听器以折叠菜单。

并且您有一个同级按钮元素。单击您想要保持菜单展开,对吗?因此,这就是使用.containsinonClick来检查我们是否在特定 范围之外ToggleMenuItems但在特定 范围内被点击的点Button。它不起作用的原因:<Button>是自定义的基于类的 React 组件,因此它在 ref 中返回 React 组件实例。而且它没有任何特定于 DOM 的方法,例如.contains

您可以修改当前的方法:如果Button已单击,则停止冒泡事件。它将停止设置的全局事件处理程序ToggleMenuItems进行反应。

const stopPropagation = (event) => event.stopPropagation();

const ToggleMenuList = ({ navAdminList, navAdminItems, classes }) => {
  const [activeId, setActiveId] = useState(null);
  const anchorRef = useRef(null);
  const handleToggle = id => {
    setActiveId(id);
  };
  const handleClose = event => {
    setActiveId(null);
  };

  return (
    <React.Fragment>
      <div className={`nav-menu--admin ${classes.root}`}>
        {navAdminList.map(e => (
          <div key={e.id}>
            <div onClick={stopPropagation}>
              <Button
                aria-owns={activeId === e.id ? 'menu-list-grow' : undefined}
                aria-haspopup="true"
                onClick={() => handleToggle(e.id)}
              >
                {e.name}
              </Button>
            </div>
            {activeId === e.id && (
              <ToggleMenuItems
                id={e.id}
                activeId={activeId}
                handleClose={handleClose}
                anchorRef={anchorRef}
                items={navAdminItems[e.id]}
              />
            )}
          </div>
        ))}
      </div>
    </React.Fragment>
  );
};

export default withStyles(styles)(ToggleMenuList);
Run Code Online (Sandbox Code Playgroud)

我已将stopPropagation处理程序放在外面,因为它不依赖于任何内部变量。