Skip to content

Create Week10 Mission0, 1, 2#126

Open
Dawon-Y wants to merge 4 commits intomainfrom
Dawon-Y/week10
Open

Create Week10 Mission0, 1, 2#126
Dawon-Y wants to merge 4 commits intomainfrom
Dawon-Y/week10

Conversation

@Dawon-Y
Copy link
Contributor

@Dawon-Y Dawon-Y commented Dec 18, 2025

📝 미션 번호

10주차 Misson 0, 1, 2

📋 구현 사항

  • useCallback과 memo, useMemo 진행하기
  • 영화 사이트 렌더링 최적화하기
  • 영화 사이트 Vercel로 배포하기

📎 스크린샷

prac01

-.Clipchamp.mp4

prac02

-.Clipchamp.1.mp4

mission01

-.Clipchamp.2.mp4

mission02
image

https://umc-10th-mission-wendy.vercel.app/

✅ 체크리스트

  • Merge 하려는 브랜치가 올바르게 설정되어 있나요?
  • 로컬에서 실행했을 때 에러가 발생하지 않나요?
  • 불필요한 주석이 제거되었나요?
  • 코드 스타일이 일관적인가요?

@Dawon-Y Dawon-Y requested a review from woojo230 December 18, 2025 06:20
@Dawon-Y Dawon-Y self-assigned this Dec 18, 2025
@github-actions
Copy link

🤖 Gemini 코드리뷰 결과

안녕하세요, 시니어 프론트엔드 개발자입니다. 전달해주신 Pull Request diff (총 12개 파트)를 종합하여 면밀히 검토했습니다. 프로젝트의 다양한 측면을 아우르는 변경사항들이 많아, 이를 통합하여 하나의 완성된 리뷰로 정리했습니다.

전반적인 인상:
프로젝트는 React, TypeScript, Tailwind CSS를 기반으로 다양한 프론트엔드 개념(상태 관리, React 훅 최적화, 비동기 데이터 페칭 등)을 탐구하고 적용하려는 노력이 돋보입니다. 대부분의 컴포넌트는 깔끔하게 구조화되어 있으며, 타입스크립트도 비교적 잘 활용되고 있습니다. 특히 React 훅 (useState, useReducer, useCallback, useMemo) 및 React.memo를 활용한 최적화 시도는 매우 훌륭합니다.

하지만 여러 파트에서 유사한 기능(예: 장바구니)이 다른 상태 관리 라이브러리(Redux Toolkit과 Zustand)를 사용하여 구현된 것으로 보이는 부분이 있어, 이러한 불일치를 해결하는 것이 중요합니다. 또한, 여러 prac 접두사로 시작하는 디렉토리명을 통해 다양한 학습 예제를 시도하고 있음을 짐작할 수 있습니다.


1. 프로젝트 전반 및 설정 파일 리뷰

일부 PR 파트(1, 3, 5, 7, 9)에서는 src 디렉토리 내부의 .ts 또는 .tsx 파일에 대한 변경사항이 없어 코드 리뷰가 제한적이었지만, package-lock.json, .gitignore, README.md, eslint.config.js, tsconfig.json 등 프로젝트 전반에 영향을 미치는 파일들의 변경사항도 함께 고려하여 아래와 같이 통합 의견을 드립니다.

성능 문제 (전반)

  • 현재 코드 규모에서는 빌드/런타임에 심각한 성능 저하를 유발하는 부분은 발견되지 않습니다.
  • 다만, useFetch에서 객체 비교를 위해 JSON.stringify를 사용하는 경우, 복잡한 객체에 대한 딥 이퀄리티 비교 시 오버헤드가 발생할 수 있습니다. (현재 params 정도는 괜찮습니다.)

타입스크립트 문법 / 타입 개선점 (전반)

  • 환경 변수 타입 선언 부재: import.meta.env.VITE_TMDB_TOKEN을 사용하고 있으나, vite-env.d.ts에 해당 환경 변수의 타입이 명시되어 있지 않아 타입스크립트가 존재 여부나 타입을 알 수 없습니다.
  • tsconfig.app.jsonnoImplicitOverride 고려: tsconfig.app.jsonnoImplicitOverride: true 옵션을 추가하여, 메서드 오버라이드 시 override 키워드를 명시적으로 사용하도록 강제하여 코드의 명확성과 타입 안전성을 높일 수 있습니다.
  • 패키지 버전 불일치 확인: package.jsonreact, react-dom, @types/react, @types/react-dom, vite, eslint 등의 버전과 package-lock.json에 기록된 실제 설치 버전 간의 불일치가 발견됩니다. 이는 타입 검사 및 런타임 동작에 예기치 않은 문제를 일으킬 수 있습니다.

변수명, 함수명, 주석 품질 (전반)

  • 전반적으로 변수명, 함수명은 명확하고 코드의 의도를 잘 반영하고 있습니다.
  • 주석은 필요한 곳에 적절히 존재하며, 특히 학습 목적의 코드에 붙은 설명은 이해도를 높이는 데 매우 유용합니다.
  • 개발 과정에서 넣은 console.log는 프로덕션 빌드 시 제거하는 것이 좋습니다.

중복 코드 및 리팩토링 포인트 (전반)

  • Tailwind CSS 통합 및 설정: src/App.css에 일반 CSS 스타일이 정의되어 있습니다. Tailwind CSS의 유틸리티-퍼스트 접근 방식을 완전히 활용하고 스타일링 일관성을 위해, 이 규칙들을 Tailwind 유틸리티 클래스로 변환하거나 @apply 지시어를 사용하는 것을 고려해볼 수 있습니다. 또한, tailwind.config.js 파일이 보이지 않으므로, 이를 추가하여 커스터마이징 및 최적화를 관리하는 것을 권장합니다.
  • 사용되지 않는 의존성 확인: package.jsonreact-hook-formzod가 추가되어 있지만, 현재 PR의 src 코드에서는 이 라이브러리들이 사용된 흔적이 없습니다. 사용 계획이 없다면 제거를 고려하고, 계획이 있다면 PR 설명에 명시하는 것이 좋습니다.
  • 경로 별칭(Path Aliases) 사용 고려: 프로젝트 규모가 커지면 ../../../와 같은 복잡한 상대 경로 대신 tsconfig.json에 경로 별칭을 설정하여 import CountButton from '@components/CountButton';와 같이 깔끔하게 import 할 수 있습니다.

2. 핵심 아키텍처 불일치: 장바구니 상태 관리

가장 중요한 리팩토링 포인트입니다.

src/components/CartContainer.tsx 및 관련 파일들은 Zustand를 사용하여 장바구니 상태를 관리하고 있는 반면, src/components/CartList.tsx 파일은 Redux Toolkit 관련 훅 (useAppSelector, useAppDispatch)을 사용하여 유사한 기능을 구현하고 있습니다.

이는 상태 관리 라이브러리의 혼재를 의미하며, 다음과 같은 문제를 야기합니다:

  • 코드 혼란: 개발자가 어떤 상태 관리 방식을 따라야 할지 혼동할 수 있습니다.
  • 중복 기능: CartContainer.tsx가 이미 장바구니 목록을 렌더링하고 총액을 표시하는 기능을 수행하고 있으므로, CartList.tsx는 불필요하거나 중복된 기능을 포함할 가능성이 큽니다.
  • 불필요한 의존성: 사용되지 않는 Redux 관련 의존성이 프로젝트에 남아있을 수 있습니다.

개선 제안:
상태 관리 라이브러리를 하나로 통일하는 것을 강력히 권장합니다. 만약 Zustand를 메인 상태 관리 솔루션으로 결정했다면, src/components/CartList.tsx 파일은 삭제하거나, 그 기능이 필수적이라면 CartContainer.tsx와 같은 방식으로 Zustand를 사용하도록 완전히 리팩토링해야 합니다.


3. 파일 및 기능별 상세 리뷰 및 개선 제안

3.1. 장바구니 기능 (CartContainer, CartItem, Modal, Navbar, useStore, cartItems.ts)

  • 성능: Zustand의 선택적 구독 방식은 불필요한 리렌더링을 최소화하며, useEffect의 종속성 배열 사용, key prop 사용 등은 효율적입니다. calculateTotals는 배열 순회하지만, 일반적인 장바구니 규모에서는 문제가 없습니다.
  • 타입 개선: CartItemTypeprice 필드 (src/features/cart/cartSlice.ts, src/store/useStore.ts)가 string으로 선언되어 있으나, 실제 코드에서는 Number()로 변환하여 사용하고 있습니다. pricenumber 타입으로 변경하고 src/constants/cartItems.ts의 값들도 숫자로 변경하여 타입 안전성과 가독성을 높일 수 있습니다.
  • 리팩토링:
    • 가격 포맷팅 유틸리티 함수 분리: toLocaleString()을 여러 곳에서 사용하고 있는데, src/utils 폴더 등에 formatCurrency와 같은 유틸리티 함수로 분리하여 일관된 포맷팅을 보장하고 유지보수를 용이하게 할 수 있습니다.
    • Modal 컴포넌트의 접근성(Accessibility) 강화: role="dialog", aria-modal="true", aria-labelledby 속성 추가, 포커스 트랩 구현, Escape 키 닫기 이벤트 핸들러 추가 등 모달의 접근성을 개선해야 합니다.
    • 테스트 용이성을 위한 data-testid 속성 추가: 핵심 UI 요소에 data-testid 속성을 추가하여 자동화된 UI 테스트를 안정적으로 작성할 수 있도록 합니다.
    • Navbar의 SVG 아이콘 react-icons로 대체: package.jsonreact-icons 라이브러리가 있는데도 SVG 코드를 직접 삽입하고 있습니다. react-icons에서 제공하는 아이콘으로 대체하여 라이브러리 활용도를 높이고 코드 가독성을 개선하는 것이 좋습니다.
    • src/constants/cartItems.ts 파일명 변경: 파일명을 src/constants/initialCartData.ts 또는 src/constants/defaultCartItems.ts 등으로 변경하여 파일의 목적을 더 명확하게 전달합니다.
    • calculateTotals 로직 개선 (선택 사항): increase, decrease 액션 발생 시 amounttotal을 해당 아이템의 price만큼 증감시키는 방식으로 최적화하여 calculateTotals 호출 빈도를 줄일 수 있습니다.

3.2. useState / useReducer 학습 예제 (src/pages/UseReducerCompany.tsx, src/pages/UseReducerPage.tsx)

  • 성능: useStateuseReducer의 사용이 효율적이며, 불필요한 리렌더링은 없습니다.
  • 타입 개선: IState, IAction, TActionType과 같은 접두사(I, T)는 최신 TypeScript 컨벤션에서 생략하는 경향이 있으므로 State, Action 등으로 변경을 고려할 수 있습니다.
  • 리팩토링:
    • 'use client'; 지시자 제거 고려: 현재 Vite + React 환경에서는 이 지시자가 기능적 역할을 하지 않으므로, Next.js 등 특정 프레임워크 사용 계획이 없다면 제거하는 것이 좋습니다.
    • 액션 타입을 상수로 정의하여 중복 제거: 액션 타입 문자열("CHANGE_DEPARTMENT", "INCREASE")을 enum 또는 const 객체로 정의하여 타입 정의와 dispatch 호출 시 모두 활용하면 오타를 방지하고 유지보수성을 높일 수 있습니다.
    • 초기 상태 및 하드코딩된 문자열 상수 분리: useReducer의 초기 상태 및 RESET 액션에서 사용되는 기본값, 그리고 직무명이나 에러 메시지 등 하드코딩된 문자열들을 상수로 정의하여 한 곳에서 관리하면 유지보수성과 다국어 처리 확장이 용이합니다.
    • 액션 인터페이스를 보다 견고하게 만들기 (Discriminated Union): IAction에서 payload가 특정 액션 타입에서만 필요하다면, Discriminated Union 패턴을 사용하여 타입 안전성을 높일 수 있습니다.

3.3. TMDB 영화 앱 (src/hooks/useFetch.ts, src/pages/HomePage.tsx, src/components/MovieFilter.tsx, src/pages/MovieDetailPage.tsx 등)

  • 성능: MovieFilter.tsxconsole.log는 프로덕션 빌드에서 제거해야 합니다.
  • 타입 개선:
    • 중복된 MovieMovieFilters 인터페이스: src/types/movie.ts에 정의된 타입들이 다른 컴포넌트에서 로컬로 다시 정의되어 있습니다. src/types/movie.ts를 단일 소스(Single Source of Truth)로 만들어 모든 관련 타입을 포함하고, 각 컴포넌트에서는 이를 import하여 사용해야 합니다.
  • 리팩토링:
    • useFetch 훅에 에러 상태 추가: useFetch는 현재 에러 발생 시 콘솔 로그만 남기고 있습니다. error 상태를 추가하여 UI에서 에러를 처리할 수 있도록 개선합니다.
    • MovieFilter 컴포넌트에서 공통 컴포넌트 재사용: src/components/common에 이미 정의된 Input, CheckBox, LanguageSelector 컴포넌트들을 재활용하여 코드 일관성과 재사용성을 높입니다.
    • MovieDetailPage에 실제 영화 상세 정보 불러오기 로직 추가: movieId 파라미터를 사용하여 TMDB API에서 영화 상세 정보를 불러와 화면에 표시하는 로직을 구현합니다.
    • 이미지 URL 헬퍼 함수 도입: 이미지 URL 생성을 중앙 집중화하고 유연성을 높이기 위해 getImageUrl(path, size)와 같은 헬퍼 함수를 만들어 사용합니다.
    • React Query 도입 고려: package.json@tanstack/react-query가 이미 추가되어 있는 것으로 보아, useFetch 훅을 useQuery로 대체하여 캐싱, 백그라운드 리패칭 등 데이터 관리를 더욱 강력하게 처리할 수 있습니다.

3.4. useCallback / memo 학습 예제 (src/pages/UseCallbackPage.tsx, src/components/CountButton.tsx, src/components/TextInput.tsx)

  • 성능: React.memouseCallback을 적절히 사용하여 불필요한 리렌더링을 방지하고 있습니다. 특히 함수형 업데이트를 통해 useCallback 의존성 배열에서 count 값을 제외한 것은 모범적인 활용입니다.
  • 타입 개선: 타입 정의는 깔끔하고 정확하게 사용되었습니다.
  • 리팩토링:
    • React 모듈 import 간결화: React 17+의 새로운 JSX transform 덕분에 JSX를 사용하는 파일에서 import React를 명시적으로 하지 않아도 됩니다. import { memo } from 'react';로 충분합니다.
    • h2 태그 스타일링 일관성 유지: CountButtonUseCallbackPageh2 태그 스타일링을 일관되게 적용하여 시각적 통일성을 가져갈 수 있습니다.
    • 컴포넌트 선언 스타일 일관성: 함수형 컴포넌트 선언(const ComponentName = ... vs function ComponentName()) 방식을 프로젝트 내에서 일관되게 유지하는 것이 좋습니다.

3.5. useMemo 학습 예제 (src/pages/UseMemoPage.tsx, src/components/TextInput.tsx, src/utils/math.ts)

  • 성능: findPrimes 함수와 useMemo를 통한 성능 최적화 시도는 훌륭합니다. 다만, TextInput 컴포넌트로 전달되는 handleText 함수가 useCallback으로 메모이제이션되지 않아 TextInput이 불필요하게 리렌더링되는 문제가 있습니다. findPrimesmap().filter() 대신 직접 배열에 push하는 방식이 미세하게 효율적일 수 있습니다.
  • 타입 개선: 타입 정의는 명확하고 적절하며, findPrimesas number[] 어설션도 적절합니다.
  • 리팩토링:
    • UseMemoPage.tsxhandleText 함수 useCallback으로 래핑: handleText 함수를 useCallback으로 감싸 TextInput의 불필요한 리렌더링을 방지해야 합니다.
    • UseMemoPage.tsx의 숫자 입력(limit)에 min 속성 추가: <input type="number"> 요소에 min="0" 또는 min="2" 속성을 추가하여 유효한 입력 범위를 안내하고 견고성을 높입니다.
    • UseMemoPage.tsx의 소수 리스트 섹션에 안내 메시지 추가: limit 값이 없거나 소수가 계산되지 않았을 때 사용자에게 안내 메시지를 표시하여 UX를 개선합니다.
    • utils/math.tsfindPrimes 최종 소수 수집 방식 최적화: map().filter() 대신 for 루프를 사용하여 소수들을 직접 배열에 추가하는 방식이 더 효율적일 수 있습니다.
    • utils/math.tsfindPrimes에 음수 max 값 방어 로직 추가: max 값이 음수일 때 빈 배열을 반환하는 방어 로직을 추가하여 함수를 더욱 견고하게 만듭니다.
    • App.tsxReact.StrictMode 적용 권장: 애플리케이션의 최상위 컴포넌트로서 StrictMode를 사용하여 개발 환경에서 잠재적인 문제를 조기에 발견할 수 있도록 합니다.
    • App 컴포넌트의 역할 주석 추가 및 라우팅 구조 고려: package.jsonreact-router-dom이 있는 것으로 보아, App 컴포넌트에 라우팅 구조(예: BrowserRouter, Routes)를 미리 고려하고 관련 주석을 추가하는 것이 좋습니다.
    • 애셋 가져오기 방식 및 컨벤션: public 폴더와 src/assets 폴더의 SVG 파일 사용 방식을 명확히 하고, 프로젝트 내에서 일관된 애셋 관리 컨벤션을 정하는 것이 좋습니다.

최종 정리 및 권장 사항

전반적으로 좋은 코드 베이스를 가지고 있으며, React와 TypeScript 학습에 대한 열정이 느껴집니다. 위에서 언급된 개선점들을 적용하면 코드의 품질, 유지보수성, 성능, 그리고 사용자 경험(특히 접근성)을 더욱 향상시킬 수 있을 것입니다.

가장 우선적으로 해결해야 할 과제는 "장바구니 기능의 상태 관리 라이브러리 일관성 확보"입니다. Zustand와 Redux Toolkit 중 하나를 선택하여 나머지 구현을 제거하거나 통일하는 작업을 진행해 주세요.

이 리뷰가 코드 개선에 도움이 되기를 바랍니다. 궁금한 점이 있으시면 언제든지 질문해주세요. 수고하셨습니다!

// options의 깊은 비교를 위한 ref
const optionsRef = useRef<string>('');

useEffect(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

에러 처리 및 메모리 누수 방지 추가하는 게 좋을 것 같습니다

Copy link
Collaborator

@woojo230 woojo230 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jsx 문법이 길어지는 부분은 컴포넌트 분리 해주면 가독성이 좋아질 것 같아요

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants