单击外部时反应关闭下拉菜单

Cri*_*alu 23 javascript reactjs

在 React 中构建自定义下拉菜单,并在单击外部尝试关闭它时遇到问题。
所以我创建了通用的 HOC,这样我也可以将它用于其他场合。

我似乎遇到的问题是我不知道如何将其ref从临时传递到组件。

我一直在研究forwardRef和其他语气的示例,但我无法弄清楚。
知道是否可能以及我该怎么做?

Codesandbox 演示

import React, { useState, useRef, useEffect } from "react";

export default function withClickOutside(WrappedComponent) {
  const Component = (props) => {
    const [open, setOpen] = useState(false);

    const ref = useRef();

    useEffect(() => {
      const handleClickOutside = (event) => {
        if (!ref?.current?.contains(event.target)) {
          setOpen(false);
        }
      };
      document.addEventListener("mousedown", handleClickOutside);
    }, [ref]);

    return <WrappedComponent {...props} open={open} setOpen={setOpen} ref={ref}/>;
  };

  return Component;
}

Run Code Online (Sandbox Code Playgroud)

Ama*_*pta 30

使用 React Hook 在该元素外部单击时,只需遵循 5 个步骤即可关闭菜单/更改任何元素的状态

第 1 步:导入 useRef 并定义变量

import {useRef} from "react"

const catMenu = useRef(null)
Run Code Online (Sandbox Code Playgroud)

第2步:使用React Hook进行状态改变(useState)

  const [openSlide, setopenSlide] = useState(""); 
Run Code Online (Sandbox Code Playgroud)

第 3 步:定义一个 javascript 函数来设置状态

   const closeOpenMenus = (e)=>{
    if(openSlide && !catMenu.current?.contains(e.target)){
      setopenSlide(false)
    }
}
Run Code Online (Sandbox Code Playgroud)

步骤 4:当鼠标在文档中的任意位置按下时添加事件侦听器

 document.addEventListener('mousedown',closeOpenMenus)
Run Code Online (Sandbox Code Playgroud)

步骤 5:选择目标元素 (ref={variable_name})

<div ref={catMenu}>... </div>
Run Code Online (Sandbox Code Playgroud)

  • 在步骤 2 中,您将“openSlide”变量初始化为空字符串,而在步骤 3 中,您使用 setopenSlide 将其更新为布尔值。您打算在第 2 步中将其初始化为“true”吗? (3认同)

the*_*ude 13

您需要处理ref传递的内容,以便它实际上附加到某些东西:

const Home = forwardRef(({ open, setOpen }, ref) => {
  console.log(open);

  return (
    <section ref={ref}>
      <h1>Feels good to be home!</h1>

      <button className="secondary" onClick={() => setOpen(!open)}>
        Dropdown Toggle
      </button>

      {open && (
        <ul>
          <li>One</li>
          <li>Two</li>
        </ul>
      )}
    </section>
  );
});
Run Code Online (Sandbox Code Playgroud)

编辑 React withClickOutside (分叉)


小智 13

有点不同。从你的方法来看,但是这个钩子可以用来包装你的按钮和菜单。

/**
 * This Hook can be used for detecting clicks outside the Opened Menu
 */
function useClickOutside(ref, onClickOutside) {
  useEffect(() => {
    /**
     * Invoke Function onClick outside of element
     */
    function handleClickOutside(event) {
      if (ref.current && !ref.current.contains(event.target)) {
        onClickOutside();
      }
    }
    // Bind
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // dispose
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref, onClickOutside]);
}
Run Code Online (Sandbox Code Playgroud)

用您的代码实现:

const Home = () => {
  let [open, setOpen] = useState(false);
  const wrapperRef = useRef("menu");
  useClickOutside(wrapperRef, () => {
    setOpen(false);
  });

  return (
    <section>
      <h1>Feels good to be home!</h1>
      <div ref={wrapperRef}>
        <button className="secondary" onClick={() => setOpen(!open)}>
          Dropdown Toggle
        </button>

        {open && (
          <ul>
            <li>One</li>
            <li>Two</li>
          </ul>
        )}
      </div>
    </section>
  );
};
Run Code Online (Sandbox Code Playgroud)