이미지 업로드 및 폼 데이터로 전송하기
해커톤 프로젝트를 진행하면서 역할을 분담해서 했더니 팀 프로젝트 코드인데 내가 모르는 코드가 몇개 있는 것 같아서 공부해서 이해하고 넘어가야된다는 생각이 들었다.
+ 게시글에는 보통 이미지를 첨부할 수 있게 하기 때문에 알아두면 좋겠다는 생각이 들어서 프로젝트에 팀원이 작성한 코드로 공부를 해보았다.
const insertImg = (e) => {
let reader = new FileReader();
// 업로드 파일 세팅 부분
const file = e.target.files[0];
setUploadedImage(file);
// 프리뷰 이미지 세팅 부분
if (e.target.files[0]) {
reader.readAsDataURL(e.target.files[0]);
} else {
setPreviewImg("/img/previewDefalut.svg"); // 파일 선택 취소 시 프리뷰 이미지 삭제
}
reader.onloadend = () => {
const previewImgUrl = reader.result;
if (previewImgUrl) {
setPreviewImg(previewImgUrl);
}
};
};
FileReader를 이용해 파일 입출력 하는건 처음이라 공부를 좀 해봤는데, 이 글이 제일 정리가 잘 되어있는 것 같아서 공유합니당
[JavaScript] 파일 입출력 (FileReader)
type이 file인 input태그 <input type="file" /> 또는 API 요청과 같은 File 또는 Blob 객체를 편리하게 처리할 수 있는 방법을 제공하는 객체abort, load, error와 같은 이벤트에서 발생한 프로세스를 처리하는데
velog.io
let reader = new FileReader();
setUploadedImage(e.target.files[0]);
console.log(e.target.files[0]);
생성자 함수를 이용해 FileReader 객체(파일을 읽어오는 역할)를 생성하여 reader 변수에 할당한다.
e.target.files[0]은 파일을 입력받는 input에서 선택한 파일을 나타내는데, 이를 useState상태 변수인 setUploadedImage(e.target.files[0])를 이용해 uploadedImage에 설정하여 폼 제출 시 이미지를 서버로 보낼 수 있도록 한다. 콘솔 창을 보면 아래와 같이 이미지의 정보가 나온다.
if (e.target.files[0]) {
reader.readAsDataURL(e.target.files[0]);
} else {
setPreviewImg("/img/previewDefalut.svg");
}
e.target.files[0]가 존재하는지 확인하고 true면 readAsDataURL 메서드를 이용해 선택한 파일을 데이터 URL로 변환한다.
이 데이터 URL은 미리보기 이미지로 사용된다. false면 기본 미리보기 이미지를 출력한다.
reader.onloadend = () => {
const previewImgUrl = reader.result;
console.log(previewImgUrl);
if (previewImgUrl) {
setPreviewImg(previewImgUrl);
}
};
FileReader의 onloadend 메서드는 파일 읽기가 끝나고 난 후에 실행되는 함수이다.
result 메서드를 이용해 선택한 이미지 파일의 데이터 url을 저장하고, 저장에 성공하면 previewImg 변수에 데이터를 setPreviewImg(previewImgUrl);을 이용해 저장한다.
저장에 실패했을 경우를 대비하여 성공했을 때 저장하는 방식을 사용한 것 같다.
콘솔 창을 보면 아래와 같은 정보가 출력되는데,,, 이게 이미지 파일의 데이터 url인가보다.
이미지를 첨부했으면 이제 폼 데이터로 변환하여 서버에 전송을 해야한다.
const handleSubmit = (event) => {
event.preventDefault();
const userConfirmed = window.confirm("게시글을 업로드 하시겠습니까?");
if (userConfirmed) {
const formData = new FormData();
if (uploadedImage != null) {
formData.append("image", uploadedImage);
}
formData.append("writer", 3);
formData.append("title", title);
formData.append("content", content);
postNewTip(formData);
alert("업로드 완료!");
}
};
FormData는 처음 봐서 공부를 좀 해봤는데, 이 글이 제일 정리가 잘 되어있는 것 같아서 공유합니당
🌐 FormData 사용법 & 응용 총정리 (+ fetch 전송)
FormData API 보통 서버에 데이터를 전송하기 위해서는 HTML5 의 폼 태그를 사용해 다음과 같이 메뉴를 구성하여 제출 해본 기억들이 있을 것이다. 아이디 비밀번호 성별 남자 여자 응시분야 영어 수
inpa.tistory.com
event.preventDefault();
const userConfirmed = window.confirm("게시글을 업로드 하시겠습니까?");
- submit 기본 동작을 없애고, 게시글을 업로드할지 확인하는 알림을 띄운다.
if (userConfirmed) {
const formData = new FormData(); //새로운 폼 객체 생성
if (uploadedImage != null) { // 앞서 작성한 코드를 통해 이미지를 불러왔으면
formData.append("image", uploadedImage); // 이미지 데이터 추가
}
formData.append("writer", 3); // 폼 데이터 추가
formData.append("title", title); // <input name="title" value={title}/>과 같다!
formData.append("content", content); // 동일
}
- new FormData()를 이용해 새로운 Form 객체를 생성하고 객체 안에 작성자, 제목, 내용을 데이터로 넣어준다.
postNewTip(formData); // API에 formData를 넣어서 호출
alert("업로드 완료!");
- 데이터를 추가하여 만든 formData를 api의 body부분에 할당하여 전송하면 끝!
<>
<ImgSection>
<PreviewImg src={previewImg} />
<ImgLabel htmlFor="imageInput">이미지 업로드</ImgLabel>
<ImgInput
type="file"
accept="image/*"
id="imageInput"
onChange={(e) => insertImg(e)}
/>
</ImgSection>
<SubmitBtn onClick={handleSubmit} type="submit">
게시글 업로드
</SubmitBtn>
</>
<ImgInput> 컴포넌트에 accept는 모든 이미지 파일을 넣을 수 있게 해주는 코드이다.
"image/jpeg", "image/png"등으로 원하는 형식만 설정할 수도 있다.
컴포넌트를 위 코드와 같이 설정해주면
아래와 같이 이미지를 불러오는 칸과 게시글을 업로드하는 버튼이 생기고, 이미지를 업로드하면
본인이 선택한 이미지를 확인할 수 있게 미리보기가 잘 뜨는 것을 확인할 수 있다.
게시글 업로드 버튼을 누르면 폼데이터를 서버에 전송되는 것도 확인하였다.
어려운 코드인데 잘 만들어준 우리 팀원한테 박수👏🏻👏🏻👏🏻👏🏻