커뮤니티를 구현하다가 이미지를 별도의 처리 없이 서버로 보낸 후, 가져오다 보니 로딩 시간이 많이 걸려
프론트에서 이미지를 압축한 뒤 서버로 보내어 로딩속도를 개선했습니다.
구현방법
- react, redux-toolkit 사용
- 자바스크립트 imageㄹ 리사이징 압축 라이브러리, browser-image-compression를 사용
- 총 3개의 이미지까지 보낼 수 있어서 for문을 이용
문제점
Promise로 만들어진 browser-image-compression 라이브러리를 그대로 이용하여
actionImgCompress 함수의 리턴값을 변수에 저장하니 결과값이
array가 아닌 promise {<pending>}[[prototype]]: promise[[promise state]]: "fulfilled"[[promiseresult]] 가 나와서
이미지 Blob 파일이 promiseresult에 저장이 되어있었습니다.
해결을 위하여 actionImgCompress(e.target.files[i]) 함수를 부를 때
async, await를 사용하니 바로 Blob 파일이 출력되었습니다.
input 코드
const PhotoCard = ({ onBringImg }) => {
return (
<>
<input
name="camera"
type="file"
multiple
id="camera-image"
accept="image/*"
onChange={(e) => onBringImg(e)}
className="hidden"
/>
<label htmlFor="camera-image"">
카메라
</label>
</>
);
};
export default PhotoCard;
browser-image-compression 코드
import imageCompression from 'browser-image-compression';
const actionImgCompress = async (fileSrc) => { //이미지 압축
const options = { //압축 옵션
maxSizeMB: 0.6,
maxWidthOrHeight: 1200,
useWebWorker: true,
}
try {
const compressedFile = await imageCompression(fileSrc, options)
return compressedFile
} catch (error) {
console.log(error);
}
}
input onChange 함수
const [postData, setPostData] = useState({ title: '', contents: '', camera: [] }) //서버로 보내기 위한 데이터
const [loadedImage, setLoadedImage] = useState([]) //화면 미리보기를 위한 데이터
const onBringImg = async (e) => {
let fileURLs = []
let filesLength = loadedImage.length > 0 ? 3 - loadedImage.length : e.target.files.length > 3 ? 3 : e.target.files.length
let cameraArr = []
for (let i = 0; i < filesLength; i++) {
const compressed = await actionImgCompress(e.target.files[i]) //압축 처리
cameraArr.push(compressed) //압축된 파일 배열로 보관 후 서버 보내기
setPostData({ ...postData, camera: [...postData.camera, ...cameraArr] })
let reader = new FileReader() // FileReader API로 이미지 인식
reader.readAsDataURL(e.target.files[i]) //reader에게 file을 먼저 읽히고
reader.onload = () => { // 사진 올리고 나서 처리하는 event
fileURLs[i] = reader.result
setLoadedImage([...loadedImage, ...fileURLs]) //데이터를 img src 넣어 이미지 미리보기 가능
}
}
}
서버 보내기 코드
파일을 여러개 보냈을 때, params.files.forEach((file) => formdata.append("files", file)) 으로 보내다 보니, Blob을 그대로 보냈을때 서버에서 받을 때 같은 파일로 인식하여 동일한 파일 3개가 만들어졌습니다.
코드 파라미터에 file.name을 더 보내어 문제를 해결하였습니다.
export const saveMyPost = createAsyncThunk("app/saveMyPost",
async (params) => {
const config = { headers: { "content-type": "multipart/form-data" } }
let formdata = new FormData()
formdata.append("userId", params.userId)
formdata.append("title", params.title)
formdata.append("content", params.content)
params.files.forEach((file) => formdata.append("files", file, file.name)) //file.name 추가
const res = await api.post(`주소`, formdata, config)
return res.data
})
반응형
'개발 > React' 카테고리의 다른 글
[react] 스크립트 추가하기 (0) | 2022.11.25 |
---|---|
[react] 자동 로그인 (0) | 2022.11.24 |
[react] 검색어 자동완성 구현하기 (0) | 2022.10.06 |
[react] throttle 적용하기 (0) | 2022.10.04 |
[react] react-infinite-scroll-component 사용법 (ft. 무한 스크롤) (0) | 2022.09.30 |
댓글