Next.js中点击外部隐藏下拉菜单问题及解决方法
Next.js点击外部隐藏下拉菜单的问题与解决方案
问题背景
我刚开始学习Next.js,想要实现点击下拉按钮外部时隐藏下拉菜单的功能。这段逻辑在create-react-app中运行正常,但迁移到Next.js后却无法生效,同时我想确认useEffect在Next.js中是否可以正常使用。
初始代码
逻辑部分
const LanguageRef = useRef(); const [languageDD, setLanguageDD] = useState(false); console.log(languageDD); useEffect(() => { if (!languageDD) return; const checkIfClickedOutside = (e) => { if ( languageDD && LanguageRef.current && !LanguageRef.current.contains(e.target) ) { setLanguageDD(false); } }; document.addEventListener("click", checkIfClickedOutside); return () => { // 清理事件监听器 document.removeEventListener("click", checkIfClickedOutside); }; }, [languageDD]);
触发按钮部分
<a onClick={() => setLanguageDD((prev) => !prev)}>Language </a>
问题原因
原来的代码没有排除触发下拉菜单的按钮本身:点击按钮时,事件会冒泡到document,此时languageDD已经切换为true,事件监听器会检测到点击目标不在下拉菜单(LanguageRef)内,于是立刻把languageDD设为false,导致下拉菜单刚展开就关闭。
可行解决方案
修改后的代码
const LanguageRef = useRef(); const LanguageDDRef = useRef(); const [languageDD, setLanguageDD] = useState(false); console.log(languageDD); useEffect(() => { console.log("useeffect") if (!languageDD) return; const checkIfClickedOutside = (e) => { if ( languageDD && LanguageRef.current && !LanguageRef.current.contains(e.target) && LanguageDDRef.current && !LanguageDDRef.current.contains(e.target) ) { setLanguageDD(false); } }; document.addEventListener("click", checkIfClickedOutside); return () => { // 清理事件监听器 document.removeEventListener("click", checkIfClickedOutside); }; }, [languageDD]); <a onClick={() => setLanguageDD((prev) => !prev)} ref={LanguageDDRef}>Language </a>
说明
新增LanguageDDRef绑定到触发按钮上,在点击检测逻辑中同时排除了下拉菜单和触发按钮的点击事件,这样点击按钮切换下拉状态时,不会因为事件冒泡触发外部点击的关闭逻辑。
关于useEffect的确认
useEffect在Next.js中完全可以正常使用,用法和React一致。需要注意的是,在Next.js 13+的App Router中,若使用服务器组件,需在组件顶部添加'use client'指令才能使用useEffect等客户端hooks,因为服务器组件不支持客户端交互逻辑。
内容的提问来源于stack exchange,提问作者Karthik
相关产品推荐
相关产品推荐

