🎁 모든 강의 30% + 무료 강의 선물🎁

[인프런 워밍업 스터디 클럽 3기 풀스택] 2주차 발자국

[인프런 워밍업 스터디 클럽 3기 풀스택] 2주차 발자국

🚀 Dropbox 클론코딩 - 파일 스토리지 서비스 제작하기

📚 강의 수강

일주일 동안 학습한 내용 요약

🔧 프로젝트 설정 (섹션 4-2)

  • Next.js 프로젝트 초기 설정 방법

  • Tailwind CSS와 TypeScript 환경 구성

  • Material-Tailwind, React Query 등 필요한 라이브러리 설치

  • 프로젝트 페이지 구조와 레이아웃 설정

  • 환경 변수(.env) 구성

🎨 UI 구축 (섹션 4-3)

  • Dropbox 클론의 직관적인 인터페이스 구현

  • logo.tsx, dropbox-image, search-component 등 재사용 컴포넌트 개발

  • Next.js의 이미지 처리와 정적 파일 관리

  • Tailwind CSS의 flex, grid 시스템을 활용한 반응형 디자인

  • useState 훅을 활용한 검색 기능 상태 관리

🗄 Supabase Storage 설정 및 파일 업로드 (섹션 4-4)

  • Supabase Storage 버킷 생성 및 설정

  • Form 요소와 onSubmit 이벤트를 활용한 파일 업로드 기능

  • FormData 객체를 활용한 파일 데이터 처리

  • React Query의 useMutation 훅을 통한 파일 업로드 상태 관리

  • 업로드된 이미지 URL 생성 및 표시

🔄 고급 기능 구현 (섹션 4-5)

  • Supabase Storage의 remove 함수를 활용한 파일 삭제 기능

  • react-dropzone 라이브러리를 활용한 드래그 앤 드롭 구현

  • useDropZone 훅 활용 및 onDrop 콜백 함수 설정

  • multiple 옵션을 활용한 여러 파일 동시 업로드 기능

  • Promise.all을 활용한 비동기 파일 업로드 병렬 처리

  • 로딩 상태 표시 및 사용자 피드백 개선

학습 내용 회고

이번 주 학습을 통해 Next.js와 TypeScript를 활용한 모던 웹 애플리케이션 개발 과정을 경험할 수 있었습니다. TypeScript의 타입 시스템을 적극 활용하면서 인터페이스 정의와 컴포넌트 타입 적용에 많은 배움이 있었지만, Material Tailwind 컴포넌트와의 타입 호환성 문제를 해결하는 과정에서 any 타입을 사용한 것은 아쉬움으로 남습니다.

 

 

🛠 미션 해결 과정

image

TypeScript 타입 문제 해결

Material Tailwind 컴포넌트와 TypeScript의 타입 호환성 문제에 직면했을 때, 다음과 같은 과정으로 해결했습니다:

  1. 문제 정의: IconButton, Input, Spinner 등의 컴포넌트에서 다음과 같은 TypeScript 타입 에러가 발생했습니다.

    '{ value: string; onChange: (e: ChangeEvent<HTMLInputElement>) => void; label: string; icon: Element; }' 형식에 'Pick<InputProps, ... 284 more ... | "shrink">' 형식의 onPointerEnterCapture, onPointerLeaveCapture 속성이 없습니다.
    
  2. 해결 방안 탐색: 여러 가지 해결 방법을 고려했습니다:

    • @ts-ignore 또는 @ts-expect-error 주석 사용

    • 타입 단언(Type Assertion) 사용

    • props 객체와 any 타입 활용

  3. 효율적인 접근법 선택: 코드 가독성과 유지보수성을 고려하여 props 객체와 any 타입을 활용하는 방법을 선택했습니다:

    const inputProps: any = {
      value: searchInput,
      onChange: (e: ChangeEvent<HTMLInputElement>) => setSearchInput(e.target.value),
      label: "Search Images",
      icon: <i className="fa-solid fa-magnifying-glass" />
    };
    return <MaterialInput {...inputProps} />;
    
  4. 일관된 패턴 적용: 비슷한 문제가 발생하는 다른 컴포넌트에도 동일한 패턴을 적용하여 코드의 일관성을 유지했습니다. 예를 들어 IconButton, Spinner 등의 컴포넌트에도 같은 방식으로 타입 문제를 해결했습니다.

  5. 로딩 상태 처리: boolean 값 처리 문제도 해결했습니다.

    // 경고: Received `false` for a non-boolean attribute `loading`
    // 해결: loading 속성 제거 후 조건부 렌더링으로 처리
    const iconButtonProps: any = {
      onClick: () => {
        deleteFileMutation.mutate(image.name);
      },
      color: "red",
      children: deleteFileMutation.isPending ? (
        <Spinner {...spinnerProps} />
      ) : (
        <i className="fas fa-trash" />
      )
    };
    

외부 라이브러리와의 통합 과정에서는 때로는 타입 시스템을 부분적으로 우회해야 할 필요가 있다는 것을 배웠습니다.

미션 해결 회고

기능에 집중을 하다가도...
아무래도 빨간줄 에러표시가 뜨는 것이 저는 너무 신경이 쓰였던 것 같습니다. 중간중간마다 타입에러를 해결하는데 시간투자를 했었습니다. (ai에게도 많은 질문을 했습니다)

저는 결국, 에러 무시하는 방법 혹은 TypeScript를 사용하여 타입 안전한 코드를 작성하는 방법 중 타입스크립트를 적용해보는 것을 선택했습니다.

틈틈이 타입스크립트 공부도 해야할 것 같습니다.

이번 풀스택 강의가 끝나고 나서 컴포넌트 안에서 공통으로 적용하여 재사용가능한 타입으로 빼서 리팩토링 할 시간도 가져보면 좋을 것 같습니다.

그리고 프로젝트를 진행하면서 업로드 날짜 표시 기능과 한글 파일명 변환하는 작업은 하지 못한 점은 아쉬움으로 남습니다. 다른 수강생분들은 강의 따라하는 것 외에 새로운 추가 기능도 넣기도 한 것 같은데 저는 기본을 따라 가는 것에도 벅차서 추가적인 기능은 넣지 못했습니다..

복습을 좀 더 해서 빠르게 지나쳤던 용어나 코드들을 재점검해야 할 것 같습니다...

감사합니다.

댓글을 작성해보세요.


채널톡 아이콘