고민

[프로젝트] 장소 수정 시 발생하는 이미지 관련 이슈

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]);
};