![[인프런 워밍업 스터디 클럽 3기 풀스택] 2주차 발자국](https://cdn.inflearn.com/public/files/blogs/4f74a1c2-5080-440a-a1ac-0c1293bd3b40/FULL-STACK.png)
[인프런 워밍업 스터디 클럽 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
타입을 사용한 것은 아쉬움으로 남습니다.
🛠 미션 해결 과정
TypeScript 타입 문제 해결
Material Tailwind 컴포넌트와 TypeScript의 타입 호환성 문제에 직면했을 때, 다음과 같은 과정으로 해결했습니다:
문제 정의: IconButton, Input, Spinner 등의 컴포넌트에서 다음과 같은 TypeScript 타입 에러가 발생했습니다.
'{ value: string; onChange: (e: ChangeEvent<HTMLInputElement>) => void; label: string; icon: Element; }' 형식에 'Pick<InputProps, ... 284 more ... | "shrink">' 형식의 onPointerEnterCapture, onPointerLeaveCapture 속성이 없습니다.
해결 방안 탐색: 여러 가지 해결 방법을 고려했습니다:
@ts-ignore
또는@ts-expect-error
주석 사용타입 단언(Type Assertion) 사용
props 객체와
any
타입 활용
효율적인 접근법 선택: 코드 가독성과 유지보수성을 고려하여 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} />;
일관된 패턴 적용: 비슷한 문제가 발생하는 다른 컴포넌트에도 동일한 패턴을 적용하여 코드의 일관성을 유지했습니다. 예를 들어 IconButton, Spinner 등의 컴포넌트에도 같은 방식으로 타입 문제를 해결했습니다.
로딩 상태 처리: 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를 사용하여 타입 안전한 코드를 작성하는 방법 중 타입스크립트를 적용해보는 것을 선택했습니다.
틈틈이 타입스크립트 공부도 해야할 것 같습니다.
이번 풀스택 강의가 끝나고 나서 컴포넌트 안에서 공통으로 적용하여 재사용가능한 타입으로 빼서 리팩토링 할 시간도 가져보면 좋을 것 같습니다.
그리고 프로젝트를 진행하면서 업로드 날짜 표시 기능과 한글 파일명 변환하는 작업은 하지 못한 점은 아쉬움으로 남습니다. 다른 수강생분들은 강의 따라하는 것 외에 새로운 추가 기능도 넣기도 한 것 같은데 저는 기본을 따라 가는 것에도 벅차서 추가적인 기능은 넣지 못했습니다..
복습을 좀 더 해서 빠르게 지나쳤던 용어나 코드들을 재점검해야 할 것 같습니다...
감사합니다.
댓글을 작성해보세요.