React - 파일 올리기

sarang_daddy·2023년 7월 15일
0

React

목록 보기
9/26
post-thumbnail

React로 이미지 업로드 기능을 구현하는데 발생했던 버그들로 고생을 했다..
정리하고 기록해서 나중에는 벌레 잡는데 걸리는 시간을 줄이자 😅

  • 1차 구현 : 재업로드가 안되는 문제
  • 2차 구현 : 중복되는 이미지가 올라가는 문제
  • 3차 구현 : 해결

1차 구현

참고자료

화면에 업로드한 이미지 보여주기
이미지 업로드 하기
이미지 파일 업로드 하기

특이사항 (대략적인 로직 설명)

  • uploadPhoto컴포넌트는 이미지를 선택하고 선택한 이미지가 보이도록 설계했다.
  • web에 나타난 이미지의 X 버튼을 선택하면 이미지가 삭제된다.
  • 올라간 이미지 files는 부모 컴포넌트에서 Post요청을 하도록 되어있다.
  • 즉, 화면에 보이는 이미지는 실제 서버에 저장된 이미지가 아니다.
  • "완료" 버튼을 클릭하면 화면에 보이는 이미지 files가 서버에 저장된다.
// 부모 컴포넌트에게 선택된 files를 전달
  const { setPostObject } = useContext(postSalesItemContext);

// 선택된 files를 화면에 보여주기 위한 배열
  const [uploadedImages, setUploadedImages] = useState<UploadedImageType[]>([]);

// 중략

// 업로드 할 file 선택 이벤트
const handleUploadIconClick = () => {
    fileInputRef.current?.click();
  };


<S.UploadIcon onClick={handleUploadIconClick}>
	<Icon name="camera" />
	<span>
		{uploadedCount} / {maxImageCount}
	</span>
	<S.UploadInput
		type="file"
		accept="image/*" // 모든 이미지 파일 허용
		onChange={handleUploadImage} // 이미지 업로드 이벤트
		ref={fileInputRef} // input 기능 끌어오기
	/>
</S.UploadIcon>

파일 업로드

  • type="file"은 index[0]에서 file를 가지고 있는다.
    const file = event.target.files?.[0];

    console.log(event.target.files);
    console.log(file);

  • 서버에 Post하는 file이 아닌 사용자가 선택한 이미지를 바로 보여주기 위해 선택된 file을 url로 저장하고 web에서 보여준다.
const imageUrl = URL.createObjectURL(file);
const newUploadedImage: UploadedImageType = {
	id: Date.now().toString(),
	imageUrl,
	};

setUploadedImages((prevImages) => [...prevImages, newUploadedImage]);
  • 서버로 Post요청하는 이미지는 FromData로 보내야 한다.
 const handleUploadImage = (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];

    const formData = new FormData();
      formData.append('productImageUrls', file);

      setPostObject((prevPostObject: PostObjectType) => ({
        ...prevPostObject,
        files: [...(prevPostObject.files || []), formData],
      }));
    }
  };

재업로드가 안되는 문제 발생

파일을 올리고 지우고 다시 올리면 기능이 먹통이 되는 문제가 발생했다.

2차 구현

  • onChange의 문제로 판단
  • event.target.value값을 초기화

참고자료

같은 파일 두 번 입력하기

const handleUploadImage = (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];

    if (file) {
      const imageUrl = URL.createObjectURL(file);
      const newUploadedImage: UploadedImageType = {
        id: Date.now().toString(),
        imageUrl,
      };

      setUploadedImages((prevImages) => [...prevImages, newUploadedImage]);
      setUploadedCount((prevCount) => prevCount + 1);

      const formData = new FormData();
      formData.append('productImageUrls', file);

      setPostObject((prevPostObject: PostObjectType) => ({
        ...prevPostObject,
        files: [...(prevPostObject.files || []), formData],
      }));
    }

    event.target.value = '';
  };

같은 파일이 중복되서 올라가는 문제 발생

  • 지운 파일 재업로드 기능은 해결했지만 선택된 파일의 값을 초기화 했기 때문에 중복이 되는 문제가 발생

3차 구현

  • 중복 파일은 업로드를 막아주는 로직을 추가
  • imageUrl값은 초기화 되기 때문에 중복 처리 로직이 적용되지 않는다
  • 파일의 이름과 사이즈는 파일이 가지고 있는 고유 값이기 때문에 중복 처리 값으로 채택
const handleUploadImage = (event: ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];

    if (file) {
      const imageUrl = URL.createObjectURL(file);
      const isDuplicate = uploadedImages.some(
        (image) =>
          image.file.name === file.name && image.file.size === file.size,
      );

      if (isDuplicate) {
        event.target.value = '';
        return;
      }

      const newUploadedImage: UploadedImageType = {
        id: Date.now().toString(),
        imageUrl,
        file,
      };

      setUploadedImages((prevImages) => [...prevImages, newUploadedImage]);
      setUploadedCount((prevCount) => prevCount + 1);

      const formData = new FormData();
      formData.append('productImageUrls', file);

      setPostObject((prevPostObject: PostObjectType) => ({
        ...prevPostObject,
        files: [...(prevPostObject.files || []), formData],
      }));
    }
    event.target.value = '';
  };

재업로드와 중복 업로드 문제를 해결

profile
한 발자국, 한 걸음 느리더라도 하루하루 발전하는 삶을 살자.

0개의 댓글