简体   繁体   English

React JS ref (useRef):包含不是函数

[英]React JS ref (useRef): contains is not a function

I am working on a React JS project.我正在做一个 React JS 项目。 I am using hooks and functional components.我正在使用钩子和功能组件。 I am using ref.我正在使用参考。 I am using useRef because I am in a functional component.我使用 useRef 是因为我在一个功能组件中。 But the contains function is not working on ref.但是 contains 函数不适用于 ref。 Following is my code.以下是我的代码。

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

As you can see in my component, in the event listener, it is throwing the following error.正如您在我的组件中看到的,在事件侦听器中,它抛出以下错误。

Uncaught TypeError: refDialog.contains is not a function

What is wrong with my code?我的代码有什么问题?

Firstly remove typo - useRf -> useRef .首先删除错字 - useRf -> useRef Secondly - refDialog is a read-only variable, you can't overwrite it - ref={refDialog} is enough (without ref function).其次 - refDialog是一个只读变量,你不能覆盖它 - ref={refDialog}就足够了(没有 ref 函数)。 Finally - refDialog will hold an object with current field.最后 - refDialog将保存一个具有current字段的对象。 So the final condition will be:所以最终条件将是:

if (refDialog.current && refDialog.current.contains(e.target))

Dialog may not be handling refs internally. Dialog可能不会在内部处理 refs。 In such case, you can wrap it inside a div (it will not have the same exact effect, but it probably just work fine nonetheless):在这种情况下,您可以将它包装在一个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>
  );
}

Also, notice the use of useEffect , the way your code is defined, with every render, a new event listener is being created and not cleared.此外,请注意useEffect的使用,您的代码的定义方式,每次渲染时,都会创建一个新的事件侦听器而不是清除。 You probably only want to do this once when the component is created.您可能只想在创建组件时执行一次此操作。

If Dialog is a component you defined, you need to make sure the ref is being passed correctly using a forwardRef .如果 Dialog 是您定义的组件,则需要确保使用forwardRef正确传递 ref 。

const Dialog = React.forwardRef((props, ref) => (
  <div ref={ref} className="Dialog">{ props.children}</div
));

The below code should work:下面的代码应该工作:

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

You had a typo in useRef.你在 useRef 中有一个错字。 You need to check if current property exists on refDialog.您需要检查 refDialog 上是否存在当前属性。 Unlike its class counterpart, useRef hook doesn't return DOM node directly.与其对应的类不同,useRef 钩子不直接返回 DOM 节点。

Here is the working version of your problem,这是您的问题的工作版本,

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM