React 下拉菜单只切换一次
Posted
技术标签:
【中文标题】React 下拉菜单只切换一次【英文标题】:React dropdown toggles only once 【发布时间】:2020-04-15 10:25:49 【问题描述】:我正在尝试使用 useRef 钩子和 Typescript 构建 React Dropdown 组件: 如果我单击一次切换按钮或单击它外部,它会正确打开并关闭,但是当我想再次打开它时它会关闭。有任何想法吗 ?这是我以某种方式失去了参考参考吗?
这里是用法:
https://codesandbox.io/s/react-typescript-obdgs
import React, useState, useRef, useEffect from 'react'
import styled from 'styled-components'
interface Props
const DropdownMenu: React.FC<Props> = ( children ) =>
const [menuOpen, toggleMenu] = useState<boolean>(false)
const menuContent = useRef<htmlDivElement>(null)
useEffect(() =>
// console.log(menuOpen)
, [menuOpen])
const showMenu = (event: React.MouseEvent) =>
event.preventDefault()
toggleMenu(true)
document.addEventListener('click', closeMenu)
const closeMenu = (event: MouseEvent) =>
const el = event.target
if (menuContent.current)
if (el instanceof Node && !menuContent.current.contains(el))
toggleMenu(false)
document.removeEventListener('click', closeMenu)
return (
<div>
<button
onClick=(event: React.MouseEvent) =>
showMenu(event)
>
Open
</button>
menuOpen ? <div ref=menuContent>children</div> : null
</div>
)
export default DropdownMenu
【问题讨论】:
对我来说,代码沙箱工作正常。 有时能正常工作,有时不能,我不明白。 【参考方案1】:如果您单击该按钮两次,您将无法再次打开它。如果您在按钮外部单击关闭,它将按预期工作。
这可能是因为您的 showMenu 回调即使在菜单已经显示时也会执行,这会导致附加多个 closeMenu 事件侦听器,从而导致奇怪的行为。
closeMenu 事件监听器应该在效果内创建,而不是在 showMenu 回调中。
const showMenu = (event: React.MouseEvent) =>
event.preventDefault()
toggleMenu(true)
// closeMenu is the same
const closeMenu = (event: MouseEvent) =>
const el = event.target
if (menuContent.current)
if (el instanceof Node && !menuContent.current.contains(el))
toggleMenu(false)
document.removeEventListener('click', closeMenu)
useEffect(() =>
if (!menuOpen)
return
document.addEventListener('click', closeMenu)
return () =>
document.removeEventListener('click', closeMenu)
, [menuOpen])
useEffect 真的很酷——移除事件监听器的返回函数将在 menuOpen 更改和组件卸载时调用。在您之前的代码中,如果要卸载组件,则不会删除事件侦听器。
【讨论】:
谢谢,非常好的和优雅的解决方案,很好的解释。【参考方案2】:问题出在您的 onClick 按钮上。每次单击按钮时,您都在调用 showMenu
,因此您每次都在添加新的事件侦听器。
如果菜单已显示,您不想致电showMenu
,因此可以进行修复:
<button onClick=(event: React.MouseEvent) =>
if (!menuOpen) showMenu(event);
>
【讨论】:
这仍可能导致附加多个事件侦听器。状态是异步的,这意味着如果用户点击非常快,状态将没有时间更新。以上是关于React 下拉菜单只切换一次的主要内容,如果未能解决你的问题,请参考以下文章