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

React使用事件监听器切换组件时第二次点击图标无法显示搜索框

问题根因

你的代码存在两个核心问题导致二次点击失效:

  1. 事件监听绑定/移除逻辑错误:每次showSearch变化时都会新增一个document点击监听器,且绑定和移除时用的是不同的匿名函数,旧监听器根本无法被移除,多个监听器叠加后闭包捕获的旧showSearch状态发生冲突。
  2. 闭包捕获问题:事件处理函数捕获的是每次绑定时刻的showSearch值,不是最新的状态,导致判断逻辑不符合预期。

修复后代码

import ReactDOM from "react-dom";
import "@elastic/eui/dist/eui_theme_amsterdam_light.css";
import React, { useEffect, useRef, useState } from "react";
import { EuiButtonIcon, EuiFieldText } from "@elastic/eui";

const App = () => {
  const [showSearch, setShowSearch] = useState(false);
  const searchInputRef = useRef(null);
  // 存储最新的showSearch状态,避免闭包读取旧值
  const showSearchRef = useRef(showSearch);

  // 同步状态到ref
  useEffect(() => {
    showSearchRef.current = showSearch;
  }, [showSearch]);

  useEffect(() => {
    const handleClickOutside = (event) => {
      if (
        searchInputRef.current &&
        !searchInputRef.current.contains(event.target) &&
        showSearchRef.current
      ) {
        setShowSearch(false);
      }
    };
    // 只绑定一次事件
    document.addEventListener("click", handleClickOutside, false);
    // 组件卸载时移除同一个事件处理函数
    return () => {
      document.removeEventListener("click", handleClickOutside, false);
    };
  }, []);

  if (showSearch) {
    return (
      <EuiFieldText
        icon="search"
        placeholder="Sample Search Placeholder ..."
        inputRef={searchInputRef}
      />
    );
  }

  return (
    <EuiButtonIcon
      aria-label="button"
      iconType="search"
      iconSize="xxl"
      onClick={() => setShowSearch(true)}
    />
  );
};

export default App;

修改说明

  • 新增showSearchRef实时同步最新的显示状态,解决闭包读取旧值的问题
  • 全局只做一次事件绑定,用同一个函数完成绑定/移除操作,彻底避免监听器残留
  • 去掉了冗余的多监听器逻辑,运行时不会再出现状态判断冲突的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:09:03