【问题标题】:How to add event listener to the div element accessed with ref using react and typescript?如何使用 react 和 typescript 将事件侦听器添加到通过 ref 访问的 div 元素?
【发布时间】:2020-05-29 12:36:58
【问题描述】:

我想使用 ref 将事件监听器添加到 div 元素。

我将 ref div_ref 添加到 Wrapper div 并在 enableDragEventListeners 方法中访问该 div_ref 以将事件侦听器添加到 componentmount 上。

下面是我的代码,

const SomeComponent: React.FC<any> = props => {
    const div_ref  = React.useRef(null);
    React.useEffect(() => {
        const enableDragEventListeners = () => {
            const div = dropRef.current;
            if (div) {
                div.addEventListener('dragenter', handleDragIn); // get error here
                div.addEventListener('dragleave', handleDragOut); //error here
                div.addEventListener('dragover', handleDrag);//error here
                div.addEventListener('drop', handleDrop);//error here
            } 
        };
        enableDragEventListeners();
    }, []);

    return (
        <Wrapper ref={div_ref}>
           {dragging && <Overlay>{props.children}</Overlay>}
        </Wrapper>
    );
}

但我得到错误属性 addEventListener 在类型“从不”上不存在。有人可以帮我解决这个问题。谢谢。

编辑:完整的代码如下所示...我正在实现一个拖放组件,因此将其包装在想要使用它的组件周围将能够将文件拖放到其中。

const DragAndDrop: React.FC<any> = props => {
    const dropRef = useRef(null);
    const [dragging, setDragging] = useState(false);
    const [dragCounter, setDragCounter] = useState(0);
    React.useEffect(() => {
        // componentDidMount()
        const handleDrag = (e: any) => {
            if (!props.loading) {
                e.preventDefault();
                e.stopPropagation();
            }
        };

        const handleDragIn = (e: any) => {
            if (!props.loading) {
                e.preventDefault();
                e.stopPropagation();
                setDragCounter((prev: number) => prev + 1);
                if (e.dataTransfer.files) {
                    setDragging(true);
                }
            } 
        };

        const handleDragOut = (e: any) => {
            if (!props.loading) {
                e.preventDefault();
                e.stopPropagation();
                setDragCounter((prev: number) => prev - 1);
                if (dragCounter === 0) {
                    setDragging(false);
                }
            }
        };

        const handleDrop = (e: any) => {
            if (!props.loading) {
                e.preventDefault();
                e.stopPropagation();
                setDragging(false);
                if (e.dataTransfer.files && e.dataTransfer.files.length > 0){ 
                    props.handle_drop(e);
                    e.dataTransfer.clearData();
                   setDragCounter(0);
                }
            }
       };
       const enableDragEventListeners = () => {
           const div = dropRef && dropRef.current;
           if (div) {
               div.addEventListener('dragenter', handleDragIn);
               div.addEventListener('dragleave', handleDragOut);
               div.addEventListener('dragover', handleDrag);
               div.addEventListener('drop', handleDrop);
           }
       };
       const disableDragEventListeners = () => {
           const div = dropRef && dropRef.current;
           div.removeEventListener('dragenter', handleDragIn);
           div.removeEventListener('dragleave', handleDragOut);
           div.removeEventListener('dragover', handleDrag);
           div.removeEventListener('drop', handleDrop);
       };
       setDragCounter(0);
       enableDragEventListeners();
       return () => {
           // componentWillUnmount()
           disableDragEventListeners();
       };
   }, [dragCounter, props]);

   return (
       <wrapper ref={dropRef}>
           {dragging && <Overlay>{props.children}</Overlay>}
       </Wrapper>
   ); 
};

const DropZone = styled.div``;

export default DragAndDrop;

【问题讨论】:

  • 嘿,我的回答解决了你的问题吗?

标签: reactjs typescript


【解决方案1】:

问题:

const div_ref = React.useRef(null); // < --- due to null it type of div_ref becomes null 

解决方案:

const div_ref = React.useRef<any>(null); // <--- Provide type any
// OR
const div_ref = React.useRef<TYPE_OF_WRAPPER>(null); // <--- Provide the type of ref element

示例演示:(带有div元素,你可以去掉类型并检查,它会抛出同样的错误)


注意:我认为dropRef.current; 应该是div_ref.current;

【讨论】:

    【解决方案2】:

    我不确定您为什么要通过组件的 ref 手动添加这些事件侦听器,但由于您是在安装组件时添加这些事件侦听器,因此您可以将这些方法绑定到合成事件。

    <Wrapper 
      ref={div_ref}
      onDragEnter={handleDragIn}
      onDragLeave={handleDragOut}
      onDragover={handleDrag};
      onDrop={handleDrop}
    >
    

    【讨论】:

    • 谢谢。我已经用完整的代码更新了我的问题......你的解决方案是否仍然适用于代码。我认为应该但不确定为什么在挂载和卸载时添加事件侦听器不是一个好主意。
    • 潜在问题如下:您必须自己进行添加和清理代码。如果您的 handle* 函数在基于道具或状态的重新渲染时发生变化,那么您需要添加到效果的依赖数组以确保它始终触发,这意味着您需要添加清理。将它与 useEffect 一起应用会导致事件在生命周期的后期绑定,因为 useEffect 在安装发生后运行。使用 React 绑定的另一个好处是它更短、更明确、更本地化。
    • @someuser2491 是的,我已经看到你更新的代码,是的,我相信我的回答仍然适用。
    猜你喜欢
    • 1970-01-01
    • 2020-12-23
    • 2021-03-21
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多