我在React App中实现的下拉菜单出现问题。
该下拉列表基于以下文章:https://blog.campvanilla.com/reactjs-dropdown-menus-b6e06ae3a8fe
打开和关闭下拉菜单可以很好地处理下拉菜单,但是当我单击菜单中的按钮时,出现以下错误:
TypeError: Cannot read property 'contains' of null
我回到博客,发现其他人在评论中报告了相同的错误:
不错。但是仅最后一部分不起作用。 dropDownMenu保持为“空”
一种可能的解决方案是将current
添加到以下代码行:
if (!this.dropdownMenu.contains(event.target)) {
if (!this.dropdownMenu.current.contains(event.target)) {
我在StackOverflow上找到了类似的答案,其中另一个用户的下拉菜单有问题:Cannot read property 'addEventListener' of null on menu,但我仍然无法弄清错误。
import React, { Component } from 'react';
import {Link, withRouter} from 'react-router-dom'
import logo from '../images/logo.svg'
import Settings from '../lotties/Settings'
class InnerHeader extends Component {
constructor() {
super();
this.state = {
showMenu: false,
fade: false
};
this.showMenu = this.showMenu.bind(this);
this.closeMenu = this.closeMenu.bind(this);
}
showMenu(event) {
event.preventDefault();
this.setState({ showMenu: true }, () => {
document.addEventListener('click', this.closeMenu);
});
}
closeMenu(event) {
if (!this.dropdownMenu.current.contains(event.target)) {
this.setState({ showMenu: false }, () => {
document.removeEventListener('click', this.closeMenu);
});
}
}
handleLogout = () => {
localStorage.removeItem('authToken');
this.setState({
currentUser: null
})
this.props.history.push("/")
}
render() {
return (
<>
<div id="inner-header">
<div className="logo">
<Link to="/dashboard"><img src={logo} height="50px" alt="site logo" /></Link>
</div>
<div>
<button
className="menu-button"
onClick={this.showMenu}>
<Settings/>
</button>
<br />
{
this.state.showMenu
? (
<div
className="drop-down fade-in"
ref={(element) => {
this.dropdownMenu = element;
}}
>
<div className="center-it-menu">
<Link to="/account"> Account </Link>
<br />
<Link to="/integrations"> Integrations </Link>
<br />
<Link to="/tutorials"> Tutorials </Link>
<br />
<Link to="/support"> Support </Link>
<br />
<button id="menu-alert" onClick={this.handleLogout}> Logout </button>
</div>
</div>
)
: (
null
)
}
</div>
</div>
</>
)
}
}
export default withRouter(InnerHeader)
由于我仍在学习编程,因此我不想依靠库来完成此任务,也不想只是寻求解决方案。除了解决方案外,我想知道是什么原因导致的,以及如何解决该问题。由于它是您在Google上反应创建下拉菜单时显示的第一篇文章之一,因此,如果有人尝试实现此功能,我希望他们对此有一个很好的答案。
答案 0 :(得分:1)
我必须说,在所描述的场景中根本不需要ref属性。要使菜单在外部单击时折叠起来,可以使用Element.closest()
方法,该方法将遍历DOM树以在className="menu"
个祖先中找到带有event.target
的元素:
const { Component } = React,
{ render } = ReactDOM
class Card extends Component {
constructor() {
super();
this.state = {
showMenu: false,
};
this.showMenu = this.showMenu.bind(this);
this.closeMenu = this.closeMenu.bind(this);
}
showMenu(event) {
event.preventDefault();
this.setState({ showMenu: true }, () => {
document.addEventListener('click', this.closeMenu);
});
}
closeMenu(event) {
if (!event.target.closest('.menu')) {
this.setState({ showMenu: false }, () => {
document.removeEventListener('click', this.closeMenu);
});
}
}
render() {
return (
<div>
<button onClick={this.showMenu}>
Show menu
</button>
{
this.state.showMenu
? (
<div
className="menu"
>
<button> Menu item 1 </button>
<button> Menu item 2 </button>
<button> Menu item 3 </button>
</div>
)
: (
null
)
}
</div>
);
}
}
render (<Card />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
答案 1 :(得分:0)
这是因为当您不单击按钮时,此代码未执行且未启动 this.dropdownMenu ,因此它是未定义 。在这种情况下,您应该使用 onChange 事件并向其添加一个侦听器,然后在该函数中执行所需的任何操作。希望会对您有帮助。