-
[Javascript Event] Drop 이벤트에 preventDefault, stopPropagation를 적용해도 동작하지 않는 현상 해결Javascript & TypeScript 2021. 4. 27. 23:12반응형
React 프로젝트에서 파일을 Drag & Drop 하기 위한 기능을 구현하고 있었다. React를 대상으로한 Drag & Drop 컴포넌트가 오픈소스상에 많이 존재하긴 하지만, 간단한 기능 구현마저 라이브러리로 도배해야할까 싶어 직접 구현하고 있다.
(결국 진행이 간단치 않게 되었다. 🤣)
소스코드는 아래와 같다.
import React, { useState, useRef, useEffect, useCallback } from "react"; import { Container, createStyles, Grid, makeStyles, Paper, Theme, } from "@material-ui/core"; const useGridStyles = makeStyles((theme: Theme) => createStyles({ root: { flexGrow: 1, marginTop: theme.spacing(4), width: "100%" }, item: { width: "50%", }, paper: { height: 100 } }) ); function CoverMaker() { const cssGrid = useGridStyles(); return ( <Container> <Grid container className={cssGrid.root} spacing={2}> <Grid item className={cssGrid.item}> <Paper className={cssGrid.paper}> <label onDragEnter={(e) => { e.preventDefault(); e.stopPropagation(); console.log('onDragEnter')}} onDrop={(e) => { e.preventDefault(); e.stopPropagation(); console.log('drop') }} style={{ width: "100%", height: "100%", display:"block" }}> </label> <input type="file" id="mp3Upload" style={{ display: "none" }}></input> </Paper> </Grid> <Grid item className={cssGrid.item}> <Paper className={cssGrid.paper}>2</Paper> </Grid> </Grid> </Container> ); } export default CoverMaker;
metarial-ui 기반으로 개발하고 있으며, Paper 안에 label 영역에 파일을 넣으면, 숨겨진 input 태그에 파일을 등록하는 것으로 구현중 이다. 파일을 직접 브라우저에 Drag & Drop 하기 때문에, 기본동작(예를 들어, txt 파일을 drop하면 새 탭으로 txt파일이 표시되는 동작)을 막고자 preventDefault() 함수와 stopPropagation() 함수를 선 호출하도록 처리했다.
그런데 문제가 생겼다. drop 이벤트가 동작하지 않는다. 더군다나 preventDefault() 와 stopPropagation()를 사용했음에도 여전히 기본동작이 실행된다.
이에 대한 원인을 찾기위해 계속 구글링해봤지만 답을 찾을 수가 없었다. 그렇게 삽질을 거듭하다 잘 동작하는 예제소스들이 공통적으로 dragover, dragleave도 함께 사용한다는 것을 확인할 수 있었다.
혹시나 하는 마음에 dragover를 적용해보았고, "drop 이벤트가 정상동작하려면, dragover 도 반드시 필요하다"는 걸 깨닫기까지 그리 오랜 시간이 걸리지 않았다.
import React, { useState, useRef, useEffect, useCallback } from "react"; import { Container, createStyles, Grid, makeStyles, Paper, Theme, } from "@material-ui/core"; const useGridStyles = makeStyles((theme: Theme) => createStyles({ root: { flexGrow: 1, marginTop: theme.spacing(4), width: "100%" }, item: { width: "50%", }, paper: { height: 100 } }) ); function CoverMaker() { const cssGrid = useGridStyles(); return ( <Container> <Grid container className={cssGrid.root} spacing={2}> <Grid item className={cssGrid.item}> <Paper className={cssGrid.paper}> <label onDragEnter={(e) => { e.preventDefault(); e.stopPropagation(); console.log('onDragEnter')}} onDragOver={(e) => { e.preventDefault(); e.stopPropagation(); console.log('dragover') }} // 추가한 이벤트. onDrop을 위해선 반드시 필요함. onDrop={(e) => { e.preventDefault(); e.stopPropagation(); console.log('drop') }} style={{ width: "100%", height: "100%", display:"block" }}> </label> <input type="file" id="mp3Upload" style={{ display: "none" }}></input> </Paper> </Grid> <Grid item className={cssGrid.item}> <Paper className={cssGrid.paper}>2</Paper> </Grid> </Grid> </Container> ); } export default CoverMaker;
여담으로, 어떤 동작을 수행하는 함수가 preventDefault() 와 stopPropagation() 보다 앞에 있으면 안된다고 한다.
React 기준이지만, 이벤트는 javascript 기본 이벤트이므로 다른 프레임워크나, 기본 javascript에서도 공통적인 이슈가 될 거라 생각한다.
누군가 검색했을 때, 이 삽질기록이 획기적인 시간단축을 해줄 수 있길 바란다.
반응형'Javascript & TypeScript' 카테고리의 다른 글
[React] ffmpeg.wasm 메모리 누수 문제 해결 (1) 2021.05.08 [Javascript] 브라우저에서 사용하는 인코딩 및 디코딩 패키지 ffmpeg.wasm 소개 (2) 2021.05.05 [React] React Router를 적용해도 첫 메인페이지("/") 위치만 표시되는 현상 해결법 (0) 2021.04.26 [gRPC] nodeJS 에선 google.protobuf.Any 가 지원되지 않는다. (3) 2021.03.01 [NodeJS] 간단히 구현해 본 메일발송 예제 (0) 2021.02.27