1

我正在开发一个 React JS 项目。我正在使用钩子和功能组件。我正在使用参考。我使用 useRef 是因为我在一个功能组件中。但是 contains 函数不适用于 ref。以下是我的代码。

const App = () => {
    let refDialog = useRef(null);
    
    document.addEventListener('click', (e) => {
      if (refDialog && refDialog.contains(e.target)) {
         // I will do something here
      }
    })
   
    return (
      <div>
        <Dialog ref={ ref => refDialog = ref}>My dialog content</Dialog>
     </div>
    )
}

正如您在我的组件中看到的那样,在事件侦听器中,它引发了以下错误。

Uncaught TypeError: refDialog.contains is not a function

我的代码有什么问题?

4

4 回答 4

0

首先删除错字 - useRf-> useRef。其次 -refDialog是一个只读变量,你不能覆盖它 -ref={refDialog}就足够了(没有 ref 功能)。最后 -refDialog将持有一个带有current字段的对象。所以最终的条件是:

if (refDialog.current && refDialog.current.contains(e.target))
于 2020-09-30T11:12:33.520 回答
0

下面的代码应该可以工作:

import React from "react";
const App2 = () => {
  let refDialog = React.useRef(null);

  document.addEventListener("click", (e) => {
    if (
      refDialog &&
      refDialog.current &&
      refDialog.current.contains(e.target)
    ) {
      console.log("xx");
    }
  });

  return (
    <div>
      <div ref={refDialog}>My dialog content</div>
    </div>
  );
};

您在 useRef 中有错字。您需要检查 refDialog 上是否存在当前属性。与对应的类不同,useRef 钩子不直接返回 DOM 节点。

于 2020-09-30T11:35:51.083 回答
0

这是您的问题的工作版本,

import React, { useEffect } from 'react';

// YOUR OTHER IMPORT GOES HERE

const App = () => {
    const dialogRef = React.useRef(null);

    useEffect(() => {
        document.addEventListener("click", handleClickElement, false);
        // THIS WILL REMOVE THE LISTENER ON UNMOUNT
        return () => {
            document.removeEventListener("click", handleClickElement, false);
        };
    }, []);

    const handleClickElement = event => {
        if (dialogRef.current && dialogRef.current.contains(event.target)) {
            // YOUR LOGIC
            console.log("Am Clicked!")
        }
    };
    return (
        <div>
            <Dialog ref={dialogRef}>My dialog content</Dialog>
        </div>
    )
}
于 2020-09-30T11:37:20.103 回答
0

Dialog可能不会在内部处理 refs。在这种情况下,您可以将其包装在 a 中div(它不会产生完全相同的效果,但它可能仍然可以正常工作):

const App = () => {
  const refDialog = useRef(null);
    
  useEffect(() => {
    document.addEventListener('click', handleClick);
    
    return () => document.removeEventListener('click', handleClick);
  }, []);

  const handleClick = e => {
    if (refDialog.current?.contains(e.target)) {
      // I will do something here
    }
  }
   
  return (
    <div ref={refDialog}>
       <Dialog}>My dialog content</Dialog>
   </div>
  );
}

另外,请注意使用useEffect,定义代码的方式,每次渲染时,都会创建一个新的事件侦听器,而不是清除它。您可能只想在创建组件时执行一次。

如果 Dialog 是您定义的组件,则需要确保使用forwardRef正确传递 ref 。

const Dialog = React.forwardRef((props, ref) => (
  <div ref={ref} className="Dialog">{ props.children}</div
));
于 2020-09-30T11:19:23.683 回答