【问题标题】:React closing a dropdown when click outside单击外部时反应关闭下拉列表
【发布时间】:2020-08-11 13:26:03
【问题描述】:

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

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

我一直在研究 forwardRef 和其他语气的例子,但我想不通。
知道是否可能以及我该怎么做?

Codesandbox Demo

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;
}

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    您需要处理传递的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>
      );
    });
    

    【讨论】:

      【解决方案2】:

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

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

      import {useRef} from "react"
      
      const catMenu = useRef(null)
      

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

        const [openSlide, setopenSlide] = useState(""); 
      

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

         const closeOpenMenus = (e)=>{
          if(catMenu.current && openSlide && !catMenu.current.contains(e.target)){
            setopenSlide(false)
          }
      }
      

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

       document.addEventListener('mousedown',closeOpenMenus)
      

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

      <div ref={catMenu}>... </div>
      

      【讨论】:

        【解决方案3】:

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

        /**
         * This Hook can be used for detecting clicks outside the Opened Menu
         */
        function clickOutside(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]);
        }

        用您的代码实现:

        const Home = () => {
          let [open, setOpen] = useState(false);
          const wrapperRef = useRef("menu");
          outsideClickAlert(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>
          );
        };

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-23
          • 1970-01-01
          • 2019-01-05
          • 1970-01-01
          • 2023-02-23
          • 2023-01-31
          • 2021-09-01
          相关资源
          最近更新 更多