使用 React Native Web 检测组件外部的点击?

Detect click outside of component with React Native Web?

我正在使用 React Native Web。我需要检测用户何时在组件外部单击。这仅在网络上加载,因此不必在本机上运行。

我一直在尝试使用这个钩子的一个版本: https://usehooks.com/useOnClickOutside/

在我的组件中:

useOnClickOutside(ref, () => setIsOpen(false));

中钩:

function useOnClickOutside(ref, handler) {
  React.useEffect(
    () => {
      const listener = event => {
        // Do nothing if clicking ref's element or descendent elements
        if (!ref.current || ref.current.contains(event.target)) {
           return;
        }
        handler(event);
      };

      document.addEventListener("mousedown", listener);
      document.addEventListener("touchstart", listener);

      return () => {
        document.removeEventListener("mousedown", listener);
        document.removeEventListener("touchstart", listener);
      };
    },
    [ref, handler],
  );
}

这给我一个错误:

TypeError: ref.current.contains is not a function

如果我登录 ref.current 我可以看到没有 contains 方法。这是否适用于 React Native Web?

注意: 这仅适用于 react-native-web

这里是演示:https://snack.expo.io/@nomi9995/5b60ae

<View> 是基于 class 的自定义 React 组件,因此它 returns React 组件实例在 ref.而且它没有任何 DOM-specific 方法,如 .contains

您可以通过 document.getElementsByClassName()[0]

为查看和访问 dom 元素提供唯一的 class 名称
import React, { useState, useEffect, useRef } from "react";
import { StyleSheet, Text, View, Button } from "react-native";

function useOnClickOutside(ref, handler) {
  useEffect(() => {
    const listener = (event) => {
      if (!ref.current || document.getElementsByClassName("uniqueClassName")[0].contains(event.target)) {
        return;
      }
      handler(event);
    };

    document.addEventListener("mousedown", listener);
    document.addEventListener("touchstart", listener);

    return () => {
      document.removeEventListener("mousedown", listener);
      document.removeEventListener("touchstart", listener);
    };
  }, [ref, handler]);
}

export default function App() {
  const ref = useRef();

  const [isModalOpen, setModalOpen] = useState(false);

  useOnClickOutside(ref, () => setModalOpen(false));

  return (
    <View style={styles.container}>
      {isModalOpen ? (
        <View ref={ref} style={styles.modalBox} className="uniqueClassName">
          <Text style={{ color: "#FFFFFF" }}>this is modalBox</Text>
        </View>
      ) : (
        <Button onPress={() => setModalOpen(true)} title="Open Modal" />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "red",
    alignItems: "center",
    justifyContent: "center",
  },
  modalBox: {
    backgroundColor: "blue",
    height: 200,
    width: 200,
    justifyContent: "center",
    alignItems: "center",
  },
});