유저가 업로드하는 프로필 사진이나, 봉사등록 이미지를 S3에 올려 받아오기로 했다.
백엔드에서 S3에 이미지 업로드 되는 API를 만들어 둬서, 그 주소로 axios를 이용해 POST 요청을 보냈다.
(aws-sdk
를 이용해 클라이언트에서 직접 보내는 방법도 있지만 AWS access key를 직접 이용해야 하기 때문에 보안이슈가 있어 잘 사용되는 방법은 아니라고 한다.)
이 때 axios headers를 "multipart/form-data"
으로 설정해 form-data
로 보내줘야 한다. 이게 핵심!
const formData = new FormData();
formData.append("profile", fileSrc); // key, value
axios({
headers: {
"Content-Type": "multipart/form-data",
},
url: "s3으로 업로드 가능한 url 입력",
method: "POST",
data: formData,
})
.then((res) => setImageUrl(res.data)) // 미리 만들어둔 state
.catch((err) => console.log(err));
}
append
하는 부분에서 첫번째 인자인 profile
은 key
, 두번째 인자인 fileSrc
는 value
이다.
API에 S3 버킷 객체 내의 이미지가 담길 폴더명으로 key가 설정되어 있어서 profile
로 변경해주었고, 정상적으로 ImageUrl이 등록되었다.
요청에 성공한다면 서버에서는 우리가 보낸 이미지를 S3 버킷에 업로드하고, S3 내에 업로드 된 이미지 Url을 response로 보내준다.
이제 우리는 S3 버킷에 올라간 이미지 URL을 서버로부터 응답받게 된다.
이 값을 state
에 저장해 봉사등록 정보를 보낼때 다시 보내주면, 정상적으로 유저에게 뿌려줄 데이터에 s3에 등록된 이미지 url을 등록할 수 있다.
처음에는 유저가 이미지를 업로드할때마다 서버로 딱 한번만 보내야 된다는 생각에, useEffect를 이용해서
useEffect(() => {
const formData = new FormData();
formData.append("profile", fileSrc);
axios({
headers: {
"Content-Type": "multipart/form-data",
},
url: "",
method: "POST",
data: formData,
})
.then((res) => setImageUrl(res.data))
.catch((err) => console.log(err));
}
}, [fileSrc]
이런식으로 작성해줬었는데, 유저가 input 필드를 입력하면서 컴포넌트가 리렌더링 될때마다 서버로 같은 요청이 계속 갔다.
결국 S3 객체에 같은 사진이 계속해서 쌓이게 되는 꼴이었다. ^_^..
useEffect나 useCallback을 이용할 필요 없이, 유저가 사진을 업로드하는 함수 내에 로직을 작성해줘서 말끔하게 한번만 업로드 되도록 문제를 해결했다.