SSAFY에서 한 마지막 프로젝트로서 부동산 중개 플랫폼을 만든적이 있다.
사용자가 매물을 올릴때 업로드할 사진을 미리볼수 있게 사진 미리보기 기능을 구현하였었는데, 문제는 수정할 때였다.
처음 매물을 작성할때 프론트단에서 FormData 타입으로서 서버에 요청을 보낸다. 요청이 정상적으로 갔을때 서버에서는 이미지를 AWS S3에 업로드 하였다.
매물 정보를 받을때 서버는 매물 이미지의 S3 주소만을 다른 정보(매물 주소, 가격 등) 과 함께 전송해주었기에, 수정할 경우 이 S3 주소를 File형식으로 바꾸어 줘야 했다.
이 부분은 크게 어렵지 않았다. 해당 정보를 찾아본 결과 다른 블로그에서 해당 정보에 대한 글을 찾을 수 있었고 이를 활용하여 쉽게 해결하였다. 궁금하신분들은 해당 블로그에서 보시길
서버에서 받아온 기존 사진들을 FileList로 변경을 하였으니, 새롭게 추가할 사진이 있다면 이를 FileList(기존 사진들)에 추가하면 되는 간단한 일이라고 생각했다. 하지만 생각보다 간단하지 않았다....
접근법은 이러했다.
1. new DataTrasfer() 만들기
2. 기존에 사진들과 새롭게 추가할 사진들을 하나의 배열로 합치기
3. 합친 배열을 forEach를 통해 각각의 file들을 1번에서 생성한 datatrasnfer.items에 add하기
4. add가 완료 된 dataTrasfer을 setState를 통해 저장시키기
5. 새롭게 추가된 이미지 파일들을 URL.createObjectURL을 통해 변환
6. 이를 setPreviewImage에 추가
이 때만 하더라도 서버에 전송할 state와 이미지 미리보기 state를 따로 구분해서 구현하였기 때문에 쓸모 없는 작업이 많았고 이에 따라 코드도 복잡할 정도로 많았다.
이미 설정된 이미지가 있을 때 이미지 추가를 처리하는 함수를 분기함으로서, 이미 설정된 이미지가 있을때와 없을때를 구분하는 조건 하나만 필요해졌다.
readAsDataURL
은 blob을 읽고 데이터를 URL로 변환하는데 작업 시간이 필요하며 비동기식으로 동작하지만, createObjectURL
은 동기식으로 즉시 동작하여 URL을 생성하기에 속도가 더 빠르다.readAsDataURL
은 10mb createObjectURL
는 최대 800mb까지 가능하다readAsDataURL
은 많은 문자열을 포함한 base64를 리턴한다. 이는 blob url보다 많은 메모리를 사용하지만, url을 더 이상 사용하지 않을때 가비지 컬렉터에 의해 제거된다.createObjectURL
은 hash로 리턴을 하여 메모리는 상대적으로 적지만, 문서를 unload하거나 revokeObjectURL
을 실행하기 전까지 계속 메모리에 존재한다.readAsDataURL
을 사용하는게 좋아보이지만, 둘의 메모리 크기가 너무 차이가 난다.최대한 간단하게 정리한다고 정리해봤는데 너무나 복잡하고 불필요한 과정들이 많았다... 하지만 저때는 저게 나의 최선이었다.
DataTransfer
을 사용하니 코드가 불필요하게 길어져 File[]
를 사용하였다. 훨씬 가독성있고 선언적으로 코드가 구현된것을 볼 수 있다.
dataTransfer.files를 setState로 처리하는데 계속 빈 리스트를 반환하는것이었다. 왜 그럴까 하며 MDN에서 Datatransfer.fils에 대해 읽으며 아래와 같은걸 발견할수 있었다.
그렇다 drop 이벤트로만 접근할수 있는 것이었고, 그 외에는 empty가 되는것이었다. 사실 여기서 어떻게 해야 할지 전혀 감이 오지 않았다. 그래서 서버 담당자와 이야기를 해보았지만 서버쪽에서는 할 수 있는게 없었고, 결국 내가 해결을 했어야 했다.
DataTransfer가 아닌 File[] 사용하기.
DataTransfer.files는 drop 이벤트 일때만 배열을 반환하였지만, File[]은 그렇지 않았다. 왜 이걸 진작 생각하지 못했을까...
아무튼 서버에서 API를 통해 기존의 데이터를 받아온뒤 사진 url들을 File형식으로 바꾼후 forEach로 File[]에 push를 해주었다. 이후, forEach가 끝이 나면 File[]를 setState에 해줌으로써 url로 들어오던 사진들을 FileList로 변환하여 state에 저장하는것을 구현할 수 있었다.
리팩토링을 하기전의 코드들은 내가 리팩토링을 하려고 다시봤을때 이게 뭘 위한 코드인지, 무슨 작업을 하는 코드인지 이해하는데 많은 시간이 필요했다(다시보니 부끄러울 정도이다). 사진 미리보기 기능 구현과 함께 함수들을 분기함으로서, 아직 부족하지만 불필요한 코드들을 줄였고 시간이 지났을때 다시 보아도 빠르게 이해할 수 있는 코드가 되었다고 생각한다.
출처 : https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/files
https://stackoverflow.com/questions/31742072/filereader-vs-window-url-createobjecturl
https://velog.io/@kykim/readAsDataURL-vs-createObjectURL