사용할 라이브러리 :
browser-image-compression
yarn add browser-image-compression
//설치후 사용할 컴포넌트에서 import해오기
import imageCompression from 'browser-image-compression';
먼저 이미지를 업로드 할 HTML 태그를 만든다. 나는 styled-components를 사용해서 만들었다.
<UploadForm onSubmit={submit}> //form 태그
<Upload
type="file"
ref={fileInput}
onChange={getImage}
accept="image/*"/> //input태그
<SubmitButton
type="submit">
게시하기
</SubmitButton> //button 태그
</UploadForm>
버튼을 클릭했을 때, 파일을 가져온다. 이 때 주의해야 할 점은, 여타 다른 선택자로 파일을 가져와서는 안된다. onChange에서 event를 통해서 파일을 가져와야 한다는 사실을 잊지말자. 나는 이 부분 때문에 많은 시간을 허비했다...
//이미지 가져오기
const getImage = event => {
const reader = new FileReader();
const file = event.target.files[0]; //이벤트를 통해서 파일을 가져오기
actionImgCompress(file) //이미지 압축 함수
}
event.target.files[0]을 통해서 파일을 꺼낸다. 그 파일을 미리 만들어둔 actionImgCompress()에 넣어준다.
const [compressedImage, setCompressedImage] = useState(null);
//이미지 압축하기
const actionImgCompress = async fileSrc => {
console.log("압축 시작");
//압축할 옵션 내용
const options = {
maxSizeMB: 0.2,
maxWidthOrHeight: 1920,
useWebWorker: true
};
try {
//imageCompression함수의 첫번째 인자는 파일, 두번째 인자는 옵션
const compressedFile = await imageCompression(fileSrc, options);
setCompressedImage(compressedFile)
}
catch (error) {
console.log(error);
}
};
imageCompression라는 라이브러리의 함수를 사용해 이미지를 압축한다. 첫번째 인자는 가공할 대상, 두번째 인자는 가공할 내용물이다. setCompressedImage라는 미리 만들어둔 useState에 값을 넣는다. 이 compressedImage값은 formData에 넣을 것이다.
//이미지 보내기.
const submit = async event => {
event.preventDefault()
await sendFormData(compressedImage)
}
//FormData로 변환하기
const sendFormData = async(image) => {
const formData = new FormData();
//formData에 압축 이미지 파일 저장.
formData.append('image', image)
await axios
.post(`/books/9791160022988/reviews/images`,
formData ,
{headers: {'Content-Type': 'multipart/form-data',}}
)
}
sendFormData 함수를 만들고, 그 함수에 아까 압축한 compressedImage파일을 넣는다. sendFormData함수 안에서 new FormData()를 통해서 인스턴스를 생성한다. 그 다음 formData.append라는 메서드를 사용해서, key값을 설정해주고, 파일을 넣는다. 그리고 파일이 저장된 이 formData를 axios의 데이터 내용물에 넣어준다. 여기서 주의할 점이 한 가지 더 있다면, 꼭 헤더의 content-type을 넣어주어야 한다. 이렇게 해서 데이터를 전송하면 성공!!
전체 코드 :
//import 부분
import React, {useRef, useState} from "react";
import styled from "styled-components";
import imageCompression from 'browser-image-compression';
import instance from "../shared/Request";
const ReviewWrite = (props) => {
const [compressedImage, setCompressedImage] = useState(null);
//업로드 버튼 클릭하기
const selectImage = () => {
fileInput?.current.click()
}
//이미지 가져오기
const getImage = event => {
const reader = new FileReader();
const file = event.target.files[0];
actionImgCompress(file)
reader.readAsDataURL(file);
reader.onloadend = () => {
dispatch(uploadAcions.showPreview(true))
dispatch(uploadAcions.setPreview(reader.result))
}
}
//FormData로 변환하기
const sendFormData = async(image) => {
const formData = new FormData();
//formData에 압축 이미지 파일 저장.
formData.append('image', image)
const result = await instance
.post(`/books/9791160022988/reviews/images`,
formData ,
{headers: {'Content-Type': 'multipart/form-data',}}
)
return result.data
}
//이미지 보내기.
const submit = async event => {
event.preventDefault()
const result = await sendFormData(compressedImage)
}
//이미지 압축하기
const actionImgCompress = async fileSrc => {
console.log("압축 시작");
//압축할 옵션 내용
const options = {
maxSizeMB: 0.2,
maxWidthOrHeight: 1920,
useWebWorker: true
};
try {
//imageCompression함수의 첫번째 인자는 파일, 두번째 인자는 옵션
const compressedFile = await imageCompression(fileSrc, options);
setCompressedImage(compressedFile)
}
catch (error) {
console.log(error);
}
};
return (
<React.Fragment>
<UploadForm
onSubmit={submit}>
<Upload
type="file"
ref={fileInput}
onChange={getImage}
accept="image/*"/>
<SubmitButton
type="submit">
게시하기
</SubmitButton>
</UploadForm>
</React.Fragment>
)
}
참고한 자료 :
https://medium.com/@fabianopb/upload-files-with-node-and-react-to-aws-s3-in-3-steps-fdaa8581f2bd
'React' 카테고리의 다른 글
[react] propTypes - 리액트에서 type을 확인하는 방법 (0) | 2021.10.07 |
---|---|
[리액트] 왕초보 개발자의 웹성능 최적화 수기 (0) | 2021.09.04 |
[React] 리덕스의 작동원리 : 이론 (0) | 2021.07.10 |
[react] state의 3가지 정의, 리액트 콘텍스트의 2가지 단점 (0) | 2021.07.10 |
[React] 라우팅이란 (0) | 2021.06.28 |