---
title: "如何在 React 中检测元素外部点击"
description: "学习如何使用 useClickOutside Hook 在 React 中检测元素外部的点击事件。适用于模态框、下拉菜单和弹出菜单。"
canonical: https://reactuse.com/zh-Hans/blog/detect-click-outside-react/
---

# 如何在 React 中检测元素外部点击

检测元素外部的点击是 React 中最常见的 UI 交互模式之一。当用户点击页面其他位置时，关闭模态框、下拉菜单、弹出菜单和工具提示等组件，这一功能不可或缺。

<!-- truncate -->

## 问题所在

在构建下拉菜单或模态框等交互式组件时，你需要在用户点击外部区域时将其关闭。手动实现这一功能需要：

1. 添加 document 级别的点击事件监听器
2. 判断点击目标是在元素内部还是外部
3. 在组件卸载时清理监听器
4. 处理各种边界情况（Portal、嵌套元素等）

## 手动实现方式

大多数开发者从零开始实现的方式如下：

```tsx
import { useEffect, useRef } from "react";

function Dropdown() {
  const ref = useRef(null);
  const [isOpen, setIsOpen] = useState(false);

  useEffect(() => {
    function handleClick(event) {
      if (ref.current && !ref.current.contains(event.target)) {
        setIsOpen(false);
      }
    }
    document.addEventListener("mousedown", handleClick);
    return () => document.removeEventListener("mousedown", handleClick);
  }, []);

  return <div ref={ref}>{/* dropdown content */}</div>;
}
```

这种方式可以工作，但你需要在每个地方重复这段代码。而且它遗漏了触摸事件、iframe 点击和 Shadow DOM 等边界情况。

## 更好的方式：useClickOutside

[ReactUse](https://reactuse.com) 提供的 `useClickOutside` 为你处理了所有这些问题：

```tsx
import { useClickOutside } from "@reactuses/core";
import { useRef, useState } from "react";

function Dropdown() {
  const ref = useRef(null);
  const [isOpen, setIsOpen] = useState(false);

  useClickOutside(ref, () => {
    setIsOpen(false);
  });

  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Open Menu</button>
      {isOpen && (
        <div ref={ref}>
          <p>Click outside to close</p>
        </div>
      )}
    </div>
  );
}
```

## 常见使用场景

- **模态对话框** — 点击背景遮罩时关闭
- **下拉菜单** — 点击菜单外部时关闭
- **工具提示/弹出框** — 点击外部时消失
- **搜索自动补全** — 关闭建议面板
- **右键菜单** — 关闭自定义右键菜单

## 在线体验

查看我们文档站点上的[交互式演示](https://reactuse.com/element/useClickOutside/)，你可以实时编辑代码并查看效果。

## 安装

```bash
npm i @reactuses/core
```

## 相关 Hooks

- [useClickOutside 文档](https://reactuse.com/element/useClickOutside/)
- [useEventListener](https://reactuse.com/effect/useEventListener/) — 用于自定义事件处理
- [useFocus](https://reactuse.com/element/useFocus/) — 用于追踪焦点状态

---

ReactUse 提供了 100 多个 React Hooks。[查看全部 →](https://reactuse.com)