You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js实现下拉菜单报Cannot read properties of null错误求助

错误原因

  1. 你将CSS Module的导出值作为id查询DOM,但你的header.module.css中没有定义myDropdown类,styles.myDropdown实际为undefined,document.getElementById(undefined)返回null,调用classList时触发报错。
  2. CSS Module编译后类名会自动添加哈希后缀,你直接用纯字符串.dropbtn、dropdown-content做DOM匹配,无法对应到实际渲染的类名,导致点击外部关闭逻辑完全失效。
  3. 直接在组件函数体内绑定window.onclick,每次组件渲染都会覆盖之前的监听事件,且组件卸载时没有清理监听,会造成内存泄漏和逻辑冲突。
  4. React项目优先用状态控制UI,直接操作DOM不符合React的数据流逻辑,也容易出现渲染不同步的问题。

修复方案

完全采用React的状态和钩子实现下拉逻辑,无需手动操作DOM:

1. 组件代码修改

import React, { useState, useRef, useEffect } from 'react'
import Link from 'next/link'
import styles from './header.module.css'

const Header = () => {
    // 控制下拉菜单显隐状态
    const [isDropdownOpen, setIsDropdownOpen] = useState(false)
    // 绑定下拉容器DOM引用,用于判断点击区域是否在菜单外
    const dropdownRef = useRef(null)

    // 切换下拉菜单显隐
    const toggleDropdown = () => {
        setIsDropdownOpen(!isDropdownOpen)
    }

    // 监听点击外部关闭下拉
    useEffect(() => {
        const handleClickOutside = (event) => {
            if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
                setIsDropdownOpen(false)
            }
        }
        document.addEventListener('mousedown', handleClickOutside)
        // 组件卸载时清理事件监听
        return () => {
            document.removeEventListener('mousedown', handleClickOutside)
        }
    }, [])

    return (
        <div className={styles.header}>
            <div className={styles.logoLink}>
                <img src="images/itacs.png" alt="" className={styles.logo} />
            </div>
            <div className={styles.services}>
                <ul>
                    <li><Link href="/page">Docs</Link></li>
                    <li><Link href="/page">Learn</Link></li>
                    <li><Link href="/page">Projects</Link></li>
                    <li><Link href="/page">Blog</Link></li>
                    <div className={styles.dropdown} ref={dropdownRef}>
                        <button onClick={toggleDropdown} className={styles.dropbtn}>Dropdown</button>
                        {/* 根据状态动态绑定show类 */}
                        <div className={`${styles.dropdownContent} ${isDropdownOpen ? styles.show : ''}`}>
                            <a href="/">Link 1</a>
                            <a href="/">Link 2</a>
                            <a href="/">Link 3</a>
                        </div>
                    </div>
                </ul>
            </div>
            <form action="" className={styles.headerForm}>
                <a href="/" className={styles.logIn}>Log In</a>
                <a href="/" className={styles.getStarted}>Get Started</a>
            </form>
        </div>
    )
}

export default Header

2. CSS代码无需修改,原有样式可直接适配。


内容的提问来源于stack exchange,提问作者ITACS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 20:24:02