首页 > 解决方案 > 当用户使用 react 和 typescript 拖出拖动区域时,如何正确设置拖动状态?

问题描述

我希望能够将文件拖放到 DropZone div 中。当用户拖入或拖出 DropZone div 时,我希望 DropZone div 的背景颜色为灰色。

下面是我的代码,

function MainComponent () {
return (
    <Wrapper>
        <SomeOtheComponent/>
        <DragAndDrop>
            <ListContent> //this is the children for the DragAndDrop component and want this to 
                //render within DragAndDrop component
                {condition_true && (
                    <FirstList/>
                )}
                {condition_true && (
                    <SecondList/>
                )}
            </ListContent>
        </Wrapper>
    );
}


const DragAndDrop: React.FC = ({ children }) => { //here i am passing children
    const [dragging, setDragging] = useState(false);
    const [dragCounter, setDragCounter] = useState(0);

    React.useEffect(() => {
        // componentDidMount()
        setDragCounter(0);
    }, []);

    const handleDrag = (e: any) => {
        e.preventDefault();
        e.stopPropagation();
    };

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

    };

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

    const handleDrop = (e: any) => {
        e.preventDefault();
        e.stopPropagation();
        setDragging(false);
        if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
            e.dataTransfer.clearData();
            setDragCounter(0);
        }
    }; 

    return (
        <DropZone //this is a styled component div and dropzone area where user can drop files
            onDragEnter={handleDragIn}
            dragging={dragging}
            onDragLeave={handleDragOut}
            onDragOver={handleDrag}
            onDrop={handleDrop}
        >
    );
};

但是现在这工作正常,当用户将文件拖到 dropzone div 拖动状态为 true 时,现在如果用户将文件拖出 dropzone div(即 handleDragOut),则拖动状态仍然为 true。

它应该是错误的......我也不确定我是否设置正确的拖动计数器值或需要。

有人可以帮我解决这个问题。谢谢。

标签: reactjstypescript

解决方案


您的handleDragOut处理程序检查是否dragCounter为零,但此状态尚未更新。

这是一个更新的版本:

    const handleDragOut = (e: any) => {
        e.preventDefault();
        e.stopPropagation();
        setDragCounter((prev: number) => prev - 1);

        if (dragCounter > 1) return;
        setDragging(false);
    }; 

并且handleDrop应该重置计数器,无论:

  const handleDrop = (e) => {
      e.preventDefault();
      e.stopPropagation();
      setDragging(false);
      setDragCounter(0);
      if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
          e.dataTransfer.clearData();
      }
  };

在我看来,更清洁的解决方案是useRef用于柜台。这样,计数器更新不会导致不必要的渲染,并且计数器在递增/递减后立即更新。

这是一个例子:

const DragAndDrop = ({ onUpload, children }) => {
  const [isDragging, setIsDragging] = React.useState(false);

  const dragCount = React.useRef(0);

  const handleDragIn = (e) => {
    e.preventDefault();
    e.stopPropagation();

    dragCount.current++;
    setIsDragging(true);
  };

  const handleDrag = (e) => {
    e.preventDefault();
    e.stopPropagation();

    setIsDragging(true);
  };

  const handleDragOut = (e) => {
    e.preventDefault();
    e.stopPropagation();

    dragCount.current--;
    if (dragCount.current > 0) return;
    setIsDragging(false);
  };

  const handleDrop = (e) => {
    e.preventDefault();
    e.stopPropagation();

    setIsDragging(false);
    dragCount.current = 0;
    const dt = e.dataTransfer;
    const files = dt.files; // FileList

    // Handle files ...
  };

  return (
    <div
      style={{ backgroundColor: isDragging ? 'red' : 'gray', padding: '20px'}}
      onDragEnter={handleDragIn}
      onDragOver={handleDrag}
      onDragLeave={handleDragOut}
      onDrop={handleDrop}
    >
      Drag here
      <div>A nested div</div>
    </div>
  );
};

在您的情况下,不是渲染 a ,而是像以前那样div渲染样式化的组件。DropZone


推荐阅读