inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

한 입 크기로 잘라먹는 React.js 실전 프로젝트 - SNS 편

(7.4) 이미지 업로드 구현하기 2

여러 사진 중 일부 사진의 허용 사이즈 초과로 실패한 경우에 대해

해결된 질문

123

재환

작성한 질문수 1

3

안녕하세요 정환님! 항상 강의 감사한 마음으로 잘 듣고 있습니다. 이번 이미지 업로드 구현하기2 강의를 끝까지 듣고 따라하던중 스토리지에 이미지 업로드 병렬로 요청 시 제가 업로드 시도한 이미지 4장 중 1장이 허용 사이즈 초과로 스토리지 업로드 요청이 실패 했었는데요, 당연히 이미지 업로드 실패로

await deletePost(post.id);

가 호출되 post.id를 받기위해 먼저 생성한 포스트가 삭제되어 포스트 자체가 안된것처럼 동작했습니다. 근데 storage에서는 업로드 요청이 실패된 이미지를 제외하고 나머지 3장의 이미지가 저장이 되어있더라고요!

간단하게 4장 병렬 이미지 업로드 요청 > 3장 성공 1장 실패 > 이미지 업로드 일부 실패로 포스트 삭제 > storage에는 성공한 3장의 이미지만 존재, 포스트는 없음

이 상태여서 혼자 찾아봐서 추가해봤는데 맞는지도 궁금하고 맞다면 다른 분들도 비슷한 상황에서 도움이 될까 싶어 올립니다!!

images.ts 파일에 스토리지에서 이미지 삭제하는 비동기 요청 함수

export async function deleteImages(filePath: string[]) {
  const { data, error } = await supabase.storage
    .from(BUCKET_NAME)
    .remove(filePath);

  if (error) throw error;
  return data;
}

post.ts > createPostWithImages 함수 에서 try, catch문 밖에 업로드전 생성한 filePath 저장할 배열 값을 갖는 변수 선언

  const uploadedFilePaths: string[] = [];
const imageUrls = await Promise.all(
      images.map((image) => {
        const fileExtension = image.name.split(".").pop() || "webp";
        const fileName = `${Date.now()}-${crypto.randomUUID()}.${fileExtension}`;
        const filePath = `${userId}/${post.id}/${fileName}`;

        uploadedFilePaths.push(filePath);
        return uploadImage({
          file: image,
          filePath,
        });
      }),
    );

uploadImage 리턴 전에 생성한 filePath값 저장

catch문에서

if (uploadedFilePaths.length > 0) {
      await deleteImages(uploadedFilePaths);
    }

조건문 추가

최종 결과
병렬 요청중 일부의 요청이 파일의 크기 초과 등으로 실패하면
throw error >

await deletePost(post.id);
    if (uploadedFilePaths.length > 0) {
      await deleteImages(uploadedFilePaths);
    }
    throw error;


포스트 삭제, 스토리지 이미지 삭제

글을 잘 못써서 가독성이 떨어지는 부분은 양해부탁드립니다..

react typescript react-query supabase zustand

답변 2

1

재환

반영 코드 도움되시는분 있으실까 첨부합니다

export async function createPostWithImages({
  content,
  images,
  userId,
}: {
  content: string;
  images: File[];
  userId: string;
}) {
  // 1. 새로운 포스트 생성
  const post = await createPost(content);

  if (images.length === 0) return post;

  const uploadedFilePaths: string[] = [];

  try {
    // 2. 이미지 업로드

    const imageUrls = await Promise.all(
      images.map((image) => {
        const fileExtension = image.name.split(".").pop() || "webp";
        const fileName = `${Date.now()}-${crypto.randomUUID()}.${fileExtension}`;
        const filePath = `${userId}/${post.id}/${fileName}`;

        uploadedFilePaths.push(filePath);
        return uploadImage({
          file: image,
          filePath,
        });
      }),
    );

    // 3. 포스트 테이블 업데이트
    const updatedPost = await updatePost({
      id: post.id,
      image_urls: imageUrls,
    });
    return updatedPost;
  } catch (error) {
    await Promise.all([
      deletePost(post.id),
      uploadedFilePaths.length > 0
        ? deleteImages(uploadedFilePaths)
        : Promise.resolve(),
    ]);
    throw error;
  }
}

0

이정환 Winterlood

안녕하세요 재환님 이정환입니다.

앗! 그렇네요 🥲 이런 이슈가 있을 수 있겠군요

해당 이슈를 해결하려면 재환님이 말씀해주신 대로 catch 문에서 업로드 된 이미지 전체를 삭제하는 로직을 추가해주시면 됩니다!

한가지 코멘트를 남기자면 await deletePost와 await deleteImages는 Promise.all을 통해 묶어 병렬처리하면 더 깔끔할 것 같아요!

0

재환

더 깔끔한 방법 알려주셔서 감사합니다!!

회원가입 구현 (구현 후 최종 화면 출력 X)

0

65

2

(6.11) 회원가입시 프로필 정보 자동 생성하기 Q. 호출 순서 문의

0

56

1

명시적 타입 선언(콜론 타입 선언)과 as 타입 단언 차이

0

58

2

useMutation 적용 후 새로운 글 등록시 content가 안보여요

0

70

2

6.8 zustand 세션 질문입니다.

0

110

2

next.js 강의에서도 리액트 라이브러리들을 다뤄주시나요?

0

93

2

shadcn에서 radix ui와 base ui 차이는 뭔가요?

1

406

2

updateTodo 함수 생성시 화살표 함수 사용 안하는 이유

0

84

2

4.11 바로 투두 삭제가 안됨 질문

0

102

3

매개변수 updatedTodo 관련 질문

0

79

3

인증 정보가 만료되었을 때 라우트 가드 처리가 궁금합니다!

0

91

2

supabase를 사용하지 않을 경우 세션 데이터의 변경을 감지하고 스토어에 보관하는 방법이 궁금합니다!

0

85

2

4.6 id를 string으로 변경시 오류

0

74

2

리액트 타입스크립트 관련 질문있습니다.

0

71

1

소셜 로그인 구현하기 관련하여 질문이 있습니다!

0

108

2

ui 파일 질문드립니다.

0

90

1

tanstack query devtools에서 질문있습니다!

0

75

2

댓글 삭제 시 isPending 질문

0

72

2

두번째 예외상황에 대해 질문있습니다!

0

70

1

리액트 쿼리 질문입니다

1

85

2

개발자도구에서 components 가 안보입니다.

0

109

3

state 관리에 대한 정리

0

88

3

[(2.4) Shadcn/ui를 소개합니다] 강의 Shadcn 세팅 관련 질문 있습니다.

0

212

3

like 테이블에서 왜 create_at이 필요한지 궁금합니다.

0

87

1