고민
[프로젝트] 장소 수정 시 발생하는 이미지 관련 이슈
hyeone22
2024. 10. 10. 00:14
1.0. 문제 상황
- 장소 수정 기능을 구현하는 과정에서 이미지 파일 처리와 관련된 여러 문제가 발생
- 사용자가 이미지를 추가하거나 삭제할 대, 올바르게 반영되지 않거나 메모리 누수가 발생
1.1. 원인 분석
이미지 추가
- 사용자가 이미지를 추가할 때, 파일 크기나 형식에 대한 유효성 검사가 부족하여 잘못된 파일이 추가 되는 경우가 있었음
미리보기 URL 관리
- 이미지를 추가할 때 생성된 URL 객체를 적절히 관리하지 않아 메모리 누수가 발생할 수 있었다.
이미지 삭제
- 삭제된 이미지가 상태에 반영되지 않거나, 기존 이미지와 새로 추가된 이미지 간의 구분이 명확하지 않았다.
1.2. 고민 과정
파일 유효성 검사
- 이미지 파일의 크기와 형식을 검증하여 사용자가 올바른 파일만 추가할 수 있도록 해야 했다.
URL 객체 관리
- 이미지 미리보기 URL을 생성하고, 사용이 끝난 후에는 반드시 해제하여 메모리 누수를 방지해야 했다.
상태 업데이트
- 이미지 추가 및 삭제 시 상태가 올바르게 구분하고, 사용자에게 피드백을 제공해야 했다.
1.3. 해결 방법
1.3.1. 이미지 추가 로직 개선
- 이미지를 추가할 때, 파일 크기와 형식을 체크하여 유효한 파일만 추가하도록 하였다.
const handleImageAdd = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (!files || !formData) return; // files 또는 formData가 없으면 종료
// 이미지 최대 개수 제한
if (currentImage.length + files.length > 10) {
alert('이미지는 최대 10개까지 추가할 수 있습니다.');
return;
}
// 파일 유효성 검사 및 유효한 파일 배열 생성
const validFiles: File[] = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
// 파일 크기 제한
if (file.size > 1 * 1024 * 1024) {
alert('이미지 크기는 1MB를 초과할 수 없습니다.');
continue;
}
validFiles.push(file);
}
if (validFiles.length === 0) return; // 유효한 파일이 없으면 종료
setFormData({
...formData,
newImageUrl: [...(formData.newImageUrl || []), ...validFiles],
});
};
1.3.2. URL 객체 해제
- 이미지 삭제 시, 해당 URL 객체를 해제하여 메모리 누수를 방지하였다.
const handleImageDelete = (deleteUrl: string) => {
if (!formData) return;
// 현재 이미지 목록에서 삭제할 이미지 제거
setCurrentImage(currentImage.filter((img) => img !== deleteUrl));
// URL 객체 해제
if (objectUrls.current.includes(deleteUrl)) {
URL.revokeObjectURL(deleteUrl);
objectUrls.current = objectUrls.current.filter((url) => url !== deleteUrl);
} else {
setFormData({
...formData,
deleteImageUrl: [...(formData.deleteImageUrl || []), deleteUrl],
});
}
};
1.3.3. 상태 관리 최적화
- 이미지 추가 및 삭제 시 상태 업데이트 코드
const handleImageAdd = (e: React.ChangeEvent<HTMLInputElement>) => {
// ... (이전 코드 생략)
// 미리보기 URL 생성
const newImageUrls = validFiles.map((file) => {
const url = URL.createObjectURL(file);
objectUrls.current.push(url); // 생성된 URL을 ref에 저장
return url;
});
setCurrentImage([...currentImage, ...newImageUrls]);
};