티스토리 뷰

▶이미지 파일 업로드 기능 구현 - 아이콘 클릭으로 업로드하고 화면에 띄우자
이번 글에서는 프로젝트 진행 중에 겪었던 어려움을 해결한 방법에 대해 기록해 보려고 합니다 :)
다음 글에서는 업로드 후 해당 이미지 파일과 JSON 데이터를 함께 post 요청을 보내는 것까지 해볼 예정입니다.
🔎 이미지 파일 업로드
보통 이미지 파일 업로드를 하기 위해 다음과 같이 작성합니다.
<input type='file' />

해당 input 태그는 보이지 않게 하고 겉에 있는 div에 클릭 이벤트를 주어 이미지 파일 업로드 기능을 구현했는데요.
자세하게는 input 태그에 useRef를 걸어두고 겉에 있는 div에 클릭 이벤트가 발생하면 Ref를 통해 current.click() 이 되도록 코드를 작성했습니다.

input 태그는 보이지 않게 하고 아이콘을 보이도록 함으로써 사용자 입장에서는 아이콘을 누르면 파일 업로드 창이 뜨도록 화면을 구성했습니다.
이제 아이콘을 클릭 → 파일 업로드 창 → 이미지 선택
하게 되면 input 태그의 onChange 이벤트 함수가 실행되게 되는데요.
이때 이미지를 업로드 해보면서 콘솔을 찍어보면 아래와 같은데요.

사진을 여러 번 업로드 하더라도 그게 자동으로 누적이 되는 것은 아니였습니다.
이미지를 하나 업로드 하더라도 FileList 형태로 값이 들어오기 때문에 이 중에서 실제 이미지 파일에 해당하는 [0]로 state를 변경합니다.
const photoInput = useRef<HTMLInputElement>(null);
const [imgFile, setImgFile] = useState<any>('');
const handleClick = () => {
if (photoInput.current) photoInput.current.click();
};
const saveImgFile = (e: React.ChangeEvent) => {
if (photoInput.current) {
if (photoInput.current.files) {
const file = photoInput.current.files[0];
setImgFile(file);
};
};
};
return(
<div onClick={handleClick}>
<input
type="file"
accept="image/jpg, image/jpeg, image/png"
onChange={saveImgFile}
ref={photoInput}
style={{ display: 'none' }}
/>
<AiFillCamera
size="30"
style={{ position: 'absolute', marginTop: '50px', marginLeft: '-20px' }}
></AiFillCamera>
</div>
)
🔎 업로드한 이미지 화면에 띄우기
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
setView(reader.result);
};
📌 FileReader() 객체
첫 번째 줄에서 사용한 FileReder 객체는 비동기적으로 파일의 내용을 읽어들이는 데 사용됩니다.
두 번째 줄에서 사용한 메소드 readAsDataURL은 바이너리 파일을 Base64 Encode 문자열로 반환합니다.
세 번째 줄에서 사용한 이벤트 핸들러 onloaded는 읽기 동작이 끝났을 때마다 발생하는 핸들러입니다.
최종적으로 읽기 동작이 끝나면 reader.result를 통해 파일의 내용을 반환하여 화면이 바뀔 수 있도록 state를 set해주었습니다.
🔎 최종 코드 및 실행 화면
const photoInput = useRef<HTMLInputElement>(null);
const [imgFile, setImgFile] = useState<any>('');
const handleClick = () => {
if (photoInput.current) photoInput.current.click();
};
const saveImgFile = (e: React.ChangeEvent) => {
if (photoInput.current) {
if (photoInput.current.files) {
const file = photoInput.current.files[0];
setImgFile(file);
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = () => {
setView(reader.result);
};
};
};
};
return(
<div onClick={handleClick}>
<input
type="file"
accept="image/jpg, image/jpeg, image/png"
onChange={saveImgFile}
ref={photoInput}
style={{ display: 'none' }}
/>
<AiFillCamera
size="30"
style={{ position: 'absolute', marginTop: '50px', marginLeft: '-20px' }}
></AiFillCamera>
</div>
)

'프론트엔드 > React' 카테고리의 다른 글
| [React] RouterProvider로 라우터들을 효과적으로 관리하자 (0) | 2023.02.06 |
|---|---|
| [React] styled-components로 React 컴포넌트를 스타일링하자 (0) | 2023.02.05 |
| [React] 리액트 useRef 에 대해 알아보자 (2) | 2023.01.27 |
| [React] 리액트(React)를 알아보자 (0) | 2023.01.18 |
| [React] 리액트 useEffect 잘 알고 사용하자...😱 (0) | 2023.01.16 |
- Total
- Today
- Yesterday
- 자바스크립트 기초
- 자바
- JSP
- react
- 자바스크립트
- 스타일 컴포넌트 styled-components
- 리액트 훅
- CSS
- 프로젝트 회고
- 프론트엔드
- 머신러닝
- next.js
- Python
- 데이터분석
- react-query
- frontend
- rtl
- styled-components
- 파이썬
- 타입스크립트
- testing
- HTML
- 프론트엔드 공부
- 인프런
- 리액트
- jest
- 프론트엔드 기초
- TypeScript
- 딥러닝
- 디프만
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |