File drag and drop area

Renders a file drag and drop component for a single file.

  • Create a ref, called dropRef and bind it to the component's wrapper.
  • Use the useState() hook to create the drag and filename variables. Initialize them to false and '' respectively.
  • The variables dragCounter and drag are used to determine if a file is being dragged, while filename is used to store the dropped file's name.
  • Create the handleDrag, handleDragIn, handleDragOut and handleDrop methods to handle drag and drop functionality.
  • handleDrag prevents the browser from opening the dragged file. handleDragIn and handleDragOut handle the dragged file entering and exiting the component. handleDrop handles the file being dropped and passes it to onDrop.
  • Use the useEffect() hook to handle each of the drag and drop events using the previously created methods.
.filedrop {
  min-height: 120px;
  border: 3px solid #d3d3d3;
  text-align: center;
  font-size: 24px;
  padding: 32px;
  border-radius: 4px;
}

.filedrop.drag {
  border: 3px dashed #1e90ff;
}

.filedrop.ready {
  border: 3px solid #32cd32;
}
const FileDrop = ({ onDrop }) => {
  const [drag, setDrag] = React.useState(false);
  const [filename, setFilename] = React.useState('');
  let dropRef = React.createRef();
  let dragCounter = 0;

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

  const handleDragIn = e => {
    e.preventDefault();
    e.stopPropagation();
    dragCounter++;
    if (e.dataTransfer.items && e.dataTransfer.items.length > 0) setDrag(true);
  };

  const handleDragOut = e => {
    e.preventDefault();
    e.stopPropagation();
    dragCounter--;
    if (dragCounter === 0) setDrag(false);
  };

  const handleDrop = e => {
    e.preventDefault();
    e.stopPropagation();
    setDrag(false);
    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
      onDrop(e.dataTransfer.files[0]);
      setFilename(e.dataTransfer.files[0].name);
      e.dataTransfer.clearData();
      dragCounter = 0;
    }
  };

  React.useEffect(() => {
    let div = dropRef.current;
    div.addEventListener('dragenter', handleDragIn);
    div.addEventListener('dragleave', handleDragOut);
    div.addEventListener('dragover', handleDrag);
    div.addEventListener('drop', handleDrop);
    return () => {
      div.removeEventListener('dragenter', handleDragIn);
      div.removeEventListener('dragleave', handleDragOut);
      div.removeEventListener('dragover', handleDrag);
      div.removeEventListener('drop', handleDrop);
    };
  });

  return (
    <div
      ref={dropRef}
      className={
        drag ? 'filedrop drag' : filename ? 'filedrop ready' : 'filedrop'
      }
    >
      {filename && !drag ? <div>{filename}</div> : <div>Drop a file here!</div>}
    </div>
  );
};
ReactDOM.render(
  <FileDrop onDrop={console.log} />,
  document.getElementById('root')
);