首页 > 解决方案 > 使用 eventHandler 构建下拉列表。如何构造钩子+事件处理程序

问题描述

我正在使用反应和功能组件构建一个简单的下拉列表。关于奇怪的行为,我遇到的就是我们必须思考变戏法和状态的方式。这是我的组件的简化版本:

export default function App() {
  const [show, setShow] = useState(false);
  const selectElement = useRef(null);

  const handleToggle = (e) => {
    if (selectElement) {
      if (!selectElement.current.contains(e.target)) {
        setShow(!show);
      }
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleToggle, false);
    return () => document.removeEventListener("click", handleToggle, false);
  }, []);

  return (
    <div className="App">
      <div ref={selectElement} className="comp">
        <h1 onClick={() => setShow(!show)}>Select</h1>
        {show && (
          <div>
            <div>Inner 1</div>
            <div>Inner 2</div>
          </div>
        )}
      </div>
    </div>
  );
}

此组件行为错误,无法正确切换下拉菜单。效果处理程序在第一次渲染时注册并包含第一次渲染的状态(如果我在这里没有错的话)。注册的函数将不会收到状态更新。这导致了错误。

我不确定解决此问题的最佳方法是什么。目前,我决定简单地从useEffect钩子中删除依赖数组,以便在每次渲染/清理时创建和销毁效果处理程序。

我还创建了一个沙盒,因此我的问题变得更加具体。

标签: reactjsreact-hooks

解决方案


我认为这段代码将帮助您解决问题。

export default function App() {
  const [show, setShow] = useState(false);
  const selectElement = useRef(null);

  const handleToggle = (e) => {
    if (selectElement) {
      if (!selectElement.current.contains(e.target)) {
        setShow(false);
        document.removeEventListener("click", handleToggle, false);
      }
    }
  };
  const handleClick = (e) => {
    setShow(true)
    document.addEventListener("click", handleToggle, false);
  };

  return (
    <div className="App">
      <div ref={selectElement} className="comp">
        <h1 onClick={handleClick}>Select</h1>
        {show && (
          <div>
            <div>Inner 1</div>
            <div>Inner 2</div>
          </div>
        )}
      </div>
    </div>
  );
}

推荐阅读