7
votes

Détecter les crochets de réaction des composants extérieurs au clic

J'essaie d'utiliser des hooks de réaction pour déterminer si un utilisateur a cliqué en dehors d'un élément. J'utilise useRef pour obtenir une référence à l'élément.

Quelqu'un peut-il voir comment résoudre ce problème. Je reçois les erreurs suivantes et je suis les réponses d'ici .

La propriété 'contient' n'existe pas sur le type 'RefObject'

Cette erreur ci-dessus semble être un problème de typographie.

Il existe un code sandbox ici avec une erreur différente.

Dans les deux cas, cela ne fonctionne pas.

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';

const Menu = () => {
    const wrapperRef = useRef<HTMLDivElement>(null);
    const [isVisible, setIsVisible] = useState(true);

    // below is the same as componentDidMount and componentDidUnmount
    useEffect(() => {
        document.addEventListener('click', handleClickOutside, true);
        return () => {
            document.removeEventListener('click', handleClickOutside, true);
        };
    }, []);


    const handleClickOutside = event => {
       const domNode = ReactDOM.findDOMNode(wrapperRef);
       // error is coming from below
       if (!domNode || !domNode.contains(event.target)) {
          setIsVisible(false);
       }
    }

    return(
       <div ref={wrapperRef}>
         <p>Menu</p>
       </div>
    )
}


2 commentaires

Vous devriez probablement lire ceci et ceci , et ceci ... puis reconsidérez votre question.


Jetez un oeil à ma réponse de pile incl. exemple de travail avec les hooks de réaction et la détection des clics extérieurs ici: stackoverflow.com/questions/32553158/... . Cela vous aide-t-il?


3 Réponses :


21
votes

l ' API useRef doit être utilisée comme ceci:

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

function App() {
  const wrapperRef = useRef(null);
  const [isVisible, setIsVisible] = useState(true);

  // below is the same as componentDidMount and componentDidUnmount
  useEffect(() => {
    document.addEventListener("click", handleClickOutside, false);
    return () => {
      document.removeEventListener("click", handleClickOutside, false);
    };
  }, []);

  const handleClickOutside = event => {
    if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
      setIsVisible(false);
    }
  };

  return (
    isVisible && (
      <div className="menu" ref={wrapperRef}>
        <p>Menu</p>
      </div>
    )
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


0 commentaires

2
votes

Consultez cette bibliothèque sur Andarist appelée use-onclickoutside .

import * as React from 'react'
import useOnClickOutside from 'use-onclickoutside'

export default function Modal({ close }) {
  const ref = React.useRef(null)
  useOnClickOutside(ref, close)

  return <div ref={ref}>{'Modal content'}</div>
}


0 commentaires

0
votes

Une autre solution consiste à utiliser une boîte invisible plein écran.

.Menu{
    z-index: 1;
}
.Invisible{
    height: 100vh;
    left: 0;
    position: fixed;
    top: 0;
    width: 100vw;
    z-index: 0;
}

Et le CSS:

import React, { useState } from 'react';

const Menu = () => {

    const [active, setActive] = useState(false);

    return(

        <div>
            {/* The menu has z-index = 1, so it's always on top */}
            <div className = 'Menu' onClick = {() => setActive(true)}
                {active
                ? <p> Menu active   </p>
                : <p> Menu inactive </p>
                }
            </div>
            {/* This is a full-screen box with z-index = 0 */}
            {active
            ? <div className = 'Invisible' onClick = {() => setActive(false)}></div>
            : null
            }
        </div>

    );

}


0 commentaires