[React] File Drag & Drop

Hoon·2023년 8월 17일
0

React

목록 보기
3/15
post-thumbnail

지금까지 프론트엔드 개발을 하면서 여러번 구현한 기능이지만, 매번 짤때마다 까먹어서 다시 찾아보게되는 Drag & Drop ...

  • onDragOver
    - 드래그된 요소가 드롭 대상 위에 있을 때 발생
  • onDrop
    - 드래그한 요소를 드롭 대상에 놓을 때 발생

이외에도 onDragEnter, onDragLeave... 등이 있지만 아래에 구현한 Drag & Drop간소화에 포커스를 맞춰 최대한 간단하게 구현했으므로 필수적으로 필요한 위에 두개만 사용하였다. (여기서 onDrop이 제대로 동작할려면 필수적으로 onDragOver가 있어야한다.)

아래의 코드는 drag & drop을 구현한 customHooks이다.
드롭할 영역의 ref드롭되었을때 실행할 callback function을 인자로 받는다.

/**
 *  @hooks
 *  File Input Drag & Drop customHooks
 */
export default function useDragAndDrop(
  targetRef: RefObject<HTMLDivElement>,
  callback: (file: File) => void,
) {
  const handleDragOver = useCallback((e: DragEvent): void => {
    e.preventDefault();
    e.stopPropagation();
  }, []);

  const handleDrop = useCallback((e: DragEvent): void => {
    e.preventDefault();
    e.stopPropagation();

    if (e.dataTransfer) {
      const files = e.dataTransfer.files;

      if (files && files.length > 0) {
        callback(files[0]);
      }
    }
  }, []);

  useEffect(() => {
    targetRef.current?.addEventListener('dragover', handleDragOver);
    targetRef.current?.addEventListener('drop', handleDrop);

    return () => {
      targetRef.current?.removeEventListener('dragover', handleDragOver);
      targetRef.current?.removeEventListener('drop', handleDrop);
    };
  }, []);
}

위에 작성한 customHooks를 사용해서 구현한 FileInput컴포넌트이다.
drag & drop드롭할 영역인 div실제 파일을 처리할 input (type='file') 이 필요하다.
input의 경우는 파일 처리만 수행해주면 되므로 display:'none'처리를 해주었다.

export default function FileInput () {
  	const boxRef = useRef<HTMLDivElement>(null);
  	const inputRef = useRef<HTMLInputElement>(null);
  	
  	// 영역 클릭 시 display:none 되어있는 file input open
    const handleFileInputOpen = () => {
      if (inputRef.current) {
        inputRef.current.click();
      }
    };
  
  	// drag & drop customHooks
  	useDragAndDrop(componentRef, () => {
    	// 파일 업로드 logic callback function
    });
  
	return (
      <div ref={boxRef} onClick={handleFileInputOpen}>
      	<input ref={inputRef} type="file" style={{display: 'none'}} />
      </div>
    )
}
profile
개발자 Hoon입니다

1개의 댓글

comment-user-thumbnail
2023년 8월 17일

정보 감사합니다.

답글 달기