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

控制台测试React Dropdown代码时遇Cannot read properties of null报错求助

解决Dropdown点击范围判断的控制台错误问题

问题描述

在浏览器控制台测试点击是否在Dropdown组件范围内时,执行以下代码触发错误:

const dropdown = document.querySelector('w-48');

const handleClick = (event) => {
  if (dropdown.contains(event.target)) {
    console.log('Inside dropdown');
  } else {
    console.log('OUTSIDE Dropdown');
  }
}

document.addEventListener('click', handleClick, true);

错误信息:

Cannot read properties of null (reading 'contains') TypeError: Cannot read properties of null (reading 'contains') at HTMLDocument.handleClick (:4:16)

对应的React Dropdown组件代码如下:

import { useState } from "react";
import { GoChevronDown, GoChevronLeft } from "react-icons/go";
import Panel from "./Panel";

function Dropdown({ options, value, onChange }) {
  const [isOpen, setIsOpen] = useState(false);

  const handleClick = () => {
    setIsOpen(!isOpen);
  };

  const handleOptionClick = (option) => {
    // CLOSE DROPDOWN
    setIsOpen(false);
    // WHAT OPTION DID THE USER CLICK ON??
    onChange(option);
  };

  const renderedOptions = options.map((option) => {
    return (
      <div
        className='hover:g-sky-100 rounded cursor-pointer p-1'
        onClick={() => handleOptionClick(option)}
        key={option.value}
      >
        {option.label}
      </div>
    );
  });

  return (
    <div className='w-48 relative'>
      <Panel
        className='flex justify-between items-center cursor-pointer'
        onClick={handleClick}
      >
        {value?.label || "Select..."}
        {isOpen ? (
          <GoChevronDown className='text-3xl' />
        ) : (
          <GoChevronLeft className='text-3xl' />
        )}
      </Panel>
      {isOpen && <Panel className='absolute top-full'>{renderedOptions}</Panel>}
    </div>
  );
}

export default Dropdown;

预期点击Dropdown时控制台输出inside dropdown,但实际触发错误。

解决方案

1. 修复控制台代码的选择器错误

document.querySelector('w-48')写法错误,w-48是CSS类名,选择类名需要加.前缀,正确写法:

const dropdown = document.querySelector('.w-48');

如果页面中有多个w-48类的元素,建议给Dropdown根元素加唯一id(比如id="dropdown-container"),再用document.querySelector('#dropdown-container')精准选择。

2. 确保元素已挂载后再执行代码

如果在组件未渲染完成时执行控制台代码,dropdown会返回null。可以:

  • 打开Dropdown后再执行控制台代码
  • 或者用setTimeout延迟执行,确保DOM已更新:
setTimeout(() => {
  const dropdown = document.querySelector('.w-48');
  const handleClick = (event) => {
    if (dropdown.contains(event.target)) {
      console.log('Inside dropdown');
    } else {
      console.log('OUTSIDE Dropdown');
    }
  }
  document.addEventListener('click', handleClick, true);
}, 1000);

3. (可选)在React组件内直接实现判断逻辑

如果不需要控制台测试,推荐用React的useRef实现点击范围判断,更符合React开发范式:

import { useState, useRef, useEffect } from "react";
import { GoChevronDown, GoChevronLeft } from "react-icons/go";
import Panel from "./Panel";

function Dropdown({ options, value, onChange }) {
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef(null);

  const handleClick = () => {
    setIsOpen(!isOpen);
  };

  const handleOptionClick = (option) => {
    setIsOpen(false);
    onChange(option);
  };

  useEffect(() => {
    const handleDocumentClick = (event) => {
      if (dropdownRef.current && dropdownRef.current.contains(event.target)) {
        console.log('Inside dropdown');
      } else {
        console.log('OUTSIDE Dropdown');
      }
    };
    document.addEventListener('click', handleDocumentClick, true);
    return () => document.removeEventListener('click', handleDocumentClick, true);
  }, []);

  const renderedOptions = options.map((option) => {
    return (
      <div
        className='hover:g-sky-100 rounded cursor-pointer p-1'
        onClick={() => handleOptionClick(option)}
        key={option.value}
      >
        {option.label}
      </div>
    );
  });

  return (
    <div ref={dropdownRef} className='w-48 relative'>
      <Panel
        className='flex justify-between items-center cursor-pointer'
        onClick={handleClick}
      >
        {value?.label || "Select..."}
        {isOpen ? (
          <GoChevronDown className='text-3xl' />
        ) : (
          <GoChevronLeft className='text-3xl' />
        )}
      </Panel>
      {isOpen && <Panel className='absolute top-full'>{renderedOptions}</Panel>}
    </div>
  );
}

export default Dropdown;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:15:33