FileUploader 를 구현할 일이 생겨서 컴포넌트를 만드는 중 여러 이슈가 발생했고 문제를 찾았지만 이유는 아직 모르는 사항들이 있어서 정리해보고자 포스팅을 시작한다.
const fileInputRef = useRef(null);
const handleFileUploaderClick = e => {
fileInputRef.current.click();
};
const handleFileChange = e => {
const files = Array.from(e.target.files);
e.target.value = null;
};
return (
// ...
<div
className={styles.fileUploader}
onClick={handleFileUploaderClick}>
<FiFilePlus size={30} />
<input
className={styles.hiddenFileInput}
type='file'
name='fileUpload'
ref={fileInputRef}
onChange={handleFileChange}
multiple
/>
</div>
//...
);
이슈1
e.target.files[0] 이런 식으로 파일 데이터에 접근을 해서 관련 로직을 작성하는건 문제가 안생겼지만 multiple 을 지원하기 위해서 files 자체에 접근을 해서 로직을 작성하는 경우 undefined property 문제에 계속 직면했다.
해결
Array.from(e.target.files) 로 array 를 만들고 나서야 이슈를 해결할 수 있었다.
이유
이유는 how-to-convert-filelist-to-array-typescript 블로그 를 통해 금방 찾을 수 있었다.
간단히 정리하자면, e.target.files 는 FileList Object 고 해당 Object 기 때문에 .map 이나 .forEach 같은 루프 메서드를 쓸 수가 없었던 것이다.
블로그를 보면 FileList Object 는 .item() method 만 쓸 수 있게 되어있다고 되어있어서 return 값을 log 찍어 보았다.
MDN 을 참고하면 알겠지만 item 의 argument 로 찾고자 하는 file 의index 를 넣어줘야한다.
이슈2
File Pick 을 할 때, 같은 파일을 한 번더 선택하는 경우, onChange 가 트리거 되지 않는 문제가 발생했다. 똑같은 파일을 선택하고 싶은 경우 다른 파일을 선택했다가 다시 선택하는 방법 밖에는 없었다.
해결
file-input-onchange-event-not-working Blog 를 참고해서 해결했다.
간단히 정리하면, e.target.value 에 null 을 넣어주면 된다.
이유
e.target 은 이벤트가 발생한 element 다 해당 element 의 value 에 null 을 넣어주면 하위의 모든 property 가 null 로 세팅이 되기 때문에 이런 초기화 작업을 해주면 같은 file 에 대해서도 onChange 를 계속 트리거 할 수 있다.
DevTools 에서 e.target 을 Log 로 찍어보면, 내부 프로퍼티에 value 가 있어서 이 부분만 null 로 들어갈 줄 알았는데 내부 setter 에서 모두 값들을 null 로 초기화 하는 거 같다.
재미있는 부분은 혹시 null 말고 다른 값으로 초기화 할 수 있는 지 보려고 number 를 대신 넣어봤는데 다음의 오류가 발생했다.
아무래도 Input type 별로 value 에 넣을 수 있는 값들의 type 이 따로 정의되어 있는 거 같다.