Skip to content

Create Week9 Mission0~3#124

Open
dongyeol02 wants to merge 1 commit intomainfrom
dongyeol02/week09
Open

Create Week9 Mission0~3#124
dongyeol02 wants to merge 1 commit intomainfrom
dongyeol02/week09

Conversation

@dongyeol02
Copy link
Contributor

📝 미션 번호

Week9 Mission0~3

📋 구현 사항

-리듀스툴킷 및 zustand로 음원 카트 페이지 구성

📎 스크린샷

2025-12-15.8.18.10.mov

✅ 체크리스트

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

🤔 질문 사항

@dongyeol02 dongyeol02 requested a review from woojo230 December 15, 2025 11:27
@dongyeol02 dongyeol02 self-assigned this Dec 15, 2025
@github-actions
Copy link

🤖 Gemini 코드리뷰 결과

안녕하세요, 동렬님. 시니어 프론트엔드 개발자로서 제출해주신 Pull Request의 변경 사항을 면밀히 검토했습니다.
이번 리뷰는 src 디렉토리 내 .ts.tsx 파일들을 중심으로, 프로젝트 전반의 설정 파일과 컴포넌트, 상태 관리 로직을 포괄하여 진행했습니다.


PR 통합 리뷰 요약

전반적으로 기능 구현은 잘 되어 있으며, Redux Toolkit과 Zustand 사용에 대한 이해가 돋보입니다. 특히 UseReducerCompany.tsx에서 reducer 내 유효성 검사를 처리하여 상태를 제어하는 방식이 인상적입니다. 그러나 몇 가지 중대한 개선점이 발견되었습니다. 가장 핵심적인 문제는 Redux Toolkit과 Zustand 두 가지 상태 관리 라이브러리를 동시에, 심지어 동일한 관심사(장바구니, 모달)에 대해 사용하고 있다는 점입니다. 이는 코드의 복잡성을 가중시키고 유지보수를 어렵게 하며, 상태의 단일 진실 공급원을 훼손할 수 있습니다. 이외에도 TypeScript 타입 정의의 일관성, 성능 최적화, 코드 품질 및 접근성 측면에서 개선할 수 있는 부분들이 있습니다.


프로젝트 전반의 개선 제안

.ts, .tsx 파일의 품질에 직접적인 영향을 미치므로 관련된 개선 제안을 드립니다.

  1. TypeScript ESLint 설정 강화 (타입 개선점)

    • 현재 tseslint.configs.recommended를 사용하고 있지만, tseslint.configs.recommendedTypeChecked 또는 tseslint.configs.strictTypeChecked를 사용하여 타입 정보를 활용하는 Lint 규칙을 적용하면 잠재적 오류를 더욱 효과적으로 방지할 수 있습니다.
    • 제안: eslint.config.js에서 tseslint.configs.recommendedtseslint.configs.recommendedTypeChecked로 변경하고, languageOptions.parserOptions.project 설정이 tsconfig.json을 정확히 가리키는지 확인하세요.
  2. React 전용 ESLint 플러그인 추가 (코드 품질)

    • eslint-plugin-react-xeslint-plugin-react-dom을 추가하여 React 컴포넌트 작성에 대한 깊이 있는 가이드라인을 제공하고 코드 품질을 향상할 수 있습니다.
    • 제안: 해당 플러그인을 설치하고 eslint.config.jsextends 배열에 reactX.configs['recommended-typescript']reactDom.configs.recommended를 추가하세요.
  3. ecmaVersion 설정 업데이트 (코드 품질)

    • eslint.config.jslanguageOptions.ecmaVersion2020으로 설정되어 있습니다. 최신 JavaScript 문법을 정확히 파싱하고 린팅하기 위해 latest2023 등으로 업데이트하는 것이 좋습니다.
    • 제안: eslint.config.js에서 ecmaVersion: 2020ecmaVersion: 'latest' 또는 ecmaVersion: 2023으로 변경하세요.
  4. 절대 경로 임포트 설정 (리팩토링 포인트)

    • 현재 상대 경로 임포트를 사용하고 있어 프로젝트 규모가 커지면 복잡해질 수 있습니다. tsconfig.jsonvite.config.ts에서 경로 별칭(path aliases)을 설정하면 더 깔끔하고 관리하기 쉬운 절대 경로 임포트를 사용할 수 있습니다.
    • 제안: tsconfig.jsonpaths 옵션을 설정하고, vite.config.ts에도 해당 alias를 설정한 후 임포트 문을 업데이트하세요.

파일별 상세 피드백 및 개선 제안

src/App.tsx

  • 타입 개선점: App 컴포넌트의 반환 타입을 명시적으로 JSX.Element로 지정하여 가독성과 명확성을 높일 수 있습니다. (function App(): JSX.Element { 또는 const App: React.FC = () => {).
  • 코드 품질: 현재 중복 코드가 없으며 깔끔하게 작성되었습니다. <></> (Fragment) 사용도 적절합니다.

src/main.tsx

  • 타입스크립트/강건성: document.getElementById("root")!와 같은 non-null assertion(!) 사용 시, root 엘리먼트가 없을 경우 런타임 오류로 이어질 수 있습니다.
    • 제안: root 엘리먼트 존재 여부를 확인하는 방어적인 코드를 추가하세요.
  • 개발 효율: <React.StrictMode><App /> 컴포넌트를 감싸 개발 모드에서 잠재적인 문제 식별에 도움을 받을 수 있습니다.

src/page/Homepage.tsx

  • 성능 문제: CartListCartSummary 컴포넌트에 prop으로 전달되는 onIncrease, onDecrease, onClear 함수들이 매 렌더링마다 새로운 인스턴스로 생성되어 자식 컴포넌트의 불필요한 리렌더링을 유발할 수 있습니다.
    • 제안: useCallback 훅을 사용하여 이 콜백 함수들의 안정적인 참조를 보장하세요.
  • 성능/리팩토링: useSelector를 통해 state.cart 전체를 가져와 구조분해 할당하는 대신, amounttotal 같은 파생 상태는 Redux Selector (혹은 Zustand Getter)를 통해 개별적으로 가져오도록 변경하는 것이 더 효율적입니다.
  • 코드 품질: 디버깅용 console.log가 남아있습니다.
    • 제안: 프로덕션 코드에 불필요한 console.log는 제거해야 합니다.

src/component/Navbar.tsx

  • 코드 품질: 내비게이션 바를 div 태그로 사용하고 있습니다.
    • 제안: <div className="w-full ..."><nav className="w-full ...">로 변경하여 시맨틱한 HTML 구조를 따르세요.
  • 스타일링: h-25는 표준 Tailwind CSS 클래스가 아닙니다.
    • 제안: h-24 또는 h-28 등 유효한 클래스를 사용하거나, h-[6.25rem]와 같이 Arbitrary value를 사용하세요.
  • 변수명/주석: "dongyeol"이라는 텍스트가 하드코딩되어 있습니다.
    • 제안: 앱의 타이틀이라면 title prop으로 받거나 상수로 관리하여 재사용성을 높이세요.

src/component/CartList.tsx

  • 성능 문제: items.map 내부에서 onIncrease, onDecrease에 전달되는 콜백 함수 () => onIncrease(item.id)() => onDecrease(item.id)가 매 렌더링마다 새로 생성되어 CartItem 컴포넌트의 불필요한 리렌더링을 유발할 수 있습니다.
    • 제안: CartItem 컴포넌트가 onIncreaseonDecrease 함수 자체를 prop으로 받고, CartItem 내부에서 onClick={() => onIncrease(item.id)} 형태로 호출하도록 구조를 변경하여, Homepage.tsxuseCallback과 시너지를 내도록 하세요.

src/component/CartItem.tsx

  • 타입/성능: item.pricestring 타입으로 전달되어 Number(item.price).toLocaleString()으로 매 렌더링마다 변환됩니다.
    • 제안: pricenumber 타입으로 일관되게 정의하고, toLocaleString() 연산은 useMemo로 캐싱하는 것을 고려하세요.
  • 코드 품질: 파일 상단에 // components/CartItem.tsx 주석이 중복되어 있습니다.
    • 제안: 불필요한 중복 주석을 제거하세요.

src/component/CartSummary.tsx

  • 성능: totalPrice.toLocaleString() 역시 렌더링될 때마다 호출됩니다.
    • 제안: useMemo 훅을 사용하여 캐싱하는 것을 고려하세요.
  • 코드 품질: 디버깅용 console.log가 남아있습니다.
    • 제안: 프로덕션 코드에 불필요한 console.log는 제거해야 합니다.

src/component/ClearCartModal.tsx

  • UI/UX/접근성: "네" 버튼과 "아니요" 버튼의 HTML 구조가 일관되지 않아 레이아웃 정렬이 어색할 수 있습니다. 또한, 모달은 기본적인 접근성 고려사항을 추가하면 사용자 경험이 크게 향상됩니다.
    • 제안:
      1. 두 버튼을 하나의 div로 묶어 flex justify-end gap-2와 같은 스타일을 일관되게 적용합니다.
      2. 모달의 루트 divrole="dialog"aria-modal="true"를 추가하여 스크린 리더 사용자를 위한 시맨틱 정보를 제공합니다.
      3. 모달이 열렸을 때 첫 번째 상호작용 가능한 요소에 자동으로 포커스를 이동하고, 닫힐 때 원래 트리거 요소로 포커스를 복원하는 로직을 추가합니다.
      4. Escape 키를 눌러 모달을 닫을 수 있도록 이벤트 리스너를 추가합니다.
  • 코드 품질: 파일 상단에 // components/ClearCartModal.tsx 주석이 중복되어 있습니다.
    • 제안: 불필요한 중복 주석을 제거하세요.

src/constants/cartItems.ts

  • 타입 개선: price 값이 string으로 정의되어 있습니다.
    • 제안: 숫자 연산에 사용될 값이므로 number 타입으로 정의하는 것이 더 적절합니다.

src/types/cart.ts

  • 타입 개선: price: string; 부분이 핵심적인 타입 개선점입니다.
    • 제안: price: number;로 변경하고, CartItem 타입을 src/constants/cartItems.ts에서 추론하여 중앙 집중화된 src/types/cart.ts에 정의한 후 필요한 모든 곳에서 import하여 사용하도록 합니다.

src/features/cart/cartSlice.ts (Redux Toolkit 사용 시)

  • 타입 개선: pricestring인 문제점이 여전히 존재합니다.
  • 중복 코드/리팩토링/성능:
    • calcTotals 함수가 increase, decrease, removeItem 리듀서 끝에서 매번 호출되어 cartItems 전체를 순회하며 amounttotal을 재계산합니다.
    • amounttotalcartItems로부터 파생되는 값입니다. Redux Selector를 사용하여 필요할 때 계산하는 것이 더 Redux의 철학에 부합하며, 상태 불일치 위험을 줄일 수 있습니다.
    • calculateTotals 리듀서는 불필요합니다.
  • 초기 상태 불변성: initialState.cartItemscartItems 상수를 직접 참조하고 있습니다. item.amount += 1과 같이 리듀서 내에서 item 객체 속성을 변경하므로, 이 initialState를 deep copy로 만들어서 원본 cartItems 상수가 영향을 받지 않도록 하는 것이 안전합니다.

src/store/useCartStore.ts (Zustand 사용 시)

  • 성능 문제: calcTotals 함수가 increase, decrease, removeItem 액션이 발생할 때마다 amounttotal을 다시 계산하고 있습니다. 카트 아이템 수가 많아질 경우 상태 업데이트 시 매번 전체 아이템을 순회하는 비용을 고려해볼 수 있습니다.
    • 제안: increase, decrease, removeItem 액션 내에서 amounttotal을 해당 아이템의 변화량만큼만 점진적으로 업데이트하도록 로직을 수정하는 것을 고려하세요.
  • 타입 개선: CartItempricestring 타입입니다.
    • 제안: number 타입으로 변경하고, src/types/cart.ts에 정의된 중앙 집중화된 타입을 사용하도록 합니다.
  • 타입 개선: CartItem 타입이 (typeof cartItems)[number];와 같이 추론 방식으로 정의되어 있습니다.
    • 제안: src/types/cart.ts에 정의된 타입을 명시적으로 import하여 사용하는 것이 좋습니다.
  • 코드 품질: 파일 상단 주석 // src/stores/useCartStore.ts는 파일 구조가 명확하므로 제거하는 것이 좋습니다.

src/store/useModalStore.ts (Zustand 사용 시)

  • 코드 품질: 파일 상단 주석 // src/stores/useModalStore.ts는 제거하는 것이 좋습니다.

src/store/store.ts (Redux Toolkit 사용 시)

  • 타입스크립트: RootStateAppDispatch 타입 정의는 표준적이고 잘 되어 있습니다.

src/pages/UseReducerPage.tsx

  • 타입 개선점: IAction 인터페이스에서 payload를 선택적으로 정의하고 있어 reducer 내에서 undefined 가능성을 항상 고려해야 하며, 특정 type에만 payload가 필요함에도 모든 액션 타입에 payload가 존재하는 것처럼 보입니다.
    • 제안: 각 액션 type에 따라 필요한 payload를 명확히 정의하는 Discriminated Union 패턴을 사용하세요.
  • 타입/인터페이스 네이밍: IState, IActionI 접두사를 사용하고 있습니다. 현대 TypeScript 커뮤니티에서는 접두사 사용을 권장하지 않습니다.
    • 제안: State, Action과 같이 직관적인 이름을 사용하세요.
  • 코드 품질: 디버깅용 console.log 구문이 포함되어 있습니다.
    • 제안: 병합 전 반드시 제거해야 합니다.
  • 로직 일관성: INCREASE 액션 디스패치 시 payload: 3을 전달하지만, reducer는 이를 사용하지 않고 항상 1씩 증가시킵니다.
    • 제안: payload를 사용하지 않는다면 제거하거나, reducer에서 payload 값을 활용하도록 로직을 수정하세요.
  • 리팩토링: IState 인터페이스와 초기 상태에 error: string | null; 속성이 정의되어 있지만 사용되지 않습니다.
    • 제안: 사용되지 않는 상태 속성은 제거하세요.
  • 리팩토링: useReducer의 초기 상태 객체를 컴포넌트 외부에 상수로 정의하면 가독성과 유지보수성이 향상됩니다.
  • 코드 품질: onClick={(): void => ...}와 같이 콜백 함수에 명시적으로 : void를 붙이는 것은 대부분의 경우 타입스크립트가 자동으로 추론하므로 생략 가능합니다.

src/pages/UseReducerCompany.tsx

  • 타입 개선점: IAction 인터페이스의 payload 정의에 Discriminated Union 패턴을 적용하는 것이 좋습니다. (UseReducerPage.tsx와 동일한 맥락)
  • 타입/인터페이스 네이밍: IState, IAction, TActionTypeI 또는 T 접두사를 사용하고 있습니다.
    • 제안: State, Action, ActionType과 같이 직관적인 이름을 사용하세요.
  • UX 개선: 유효하지 않은 직무 입력 시 input 필드가 유효하지 않은 값을 유지하여 사용자에게 혼란을 줄 수 있습니다.
    • 제안: dispatch 호출 후, 유효성 검사 결과에 따라 input 필드의 로컬 상태를 초기화하거나 유효한 경우에만 초기화하도록 로직을 추가하여 사용자에게 명확한 피드백을 제공하는 것을 고려하세요.
  • 코드 품질: 에러 메시지를 표시하는 <p> 태그에 className="text-red-500 font-2xl" 클래스가 적용되어 있습니다. font-2xl은 표준 Tailwind CSS 클래스가 아닙니다.
    • 제안: text-2xl을 사용하세요.
  • 코드 품질: 주석 처리된 useStatechangeDepartment 로직은 제거하여 깔끔하게 유지하는 것이 좋습니다.

최종 구체적 개선 제안 (핵심 8가지)

  1. 상태 관리 라이브러리 통일 (Critical)

    • 문제: Redux Toolkit (Files: src/features/cart/cartSlice.ts, src/features/modal/modalSlice.ts, src/store/store.ts)과 Zustand (Files: src/store/useCartStore.ts, src/store/useModalStore.ts)를 동시에, 동일한 관심사(장바구니, 모달)에 대해 사용하고 있습니다. 이는 혼란, 디버깅 어려움, 유지보수 비용 증가를 야기합니다.
    • 제안: Redux Toolkit과 Zustand 중 하나를 선택하여 모든 전역 상태 관리에 일관되게 사용하도록 결정하고, 불필요한 스토어 파일과 관련 코드를 모두 제거하세요. (현재 Homepage.tsx는 Zustand 훅을 사용하므로, Zustand를 유지하고 Redux Toolkit 관련 파일을 제거하는 방향을 권장합니다.)
  2. price 필드를 number 타입으로 통일하고, 초기 로딩 시점에 한 번만 파싱하도록 변경하세요.

    • 문제: src/type/cart.tssrc/constants/cartItems.ts에서 pricestring으로 정의되어 있지만, CartItem.tsxcalcTotals 함수에서 매번 Number()로 변환하여 사용되고 있습니다.
    • 제안:
      1. src/types/cart.ts (혹은 새로 생성)의 CartItem 타입을 price: number;로 변경합니다.
      2. src/constants/cartItems.tscartItems 배열 내 모든 price 값을 숫자로 직접 변경합니다 (예: "25000" -> 25000).
      3. Zustand 스토어의 initialState (또는 Redux cartSliceinitialState)를 생성할 때, cartItems 상수를 맵핑하여 priceNumber(item.price)로 변환 후 저장합니다.
      4. src/component/CartItem.tsx에서 Number(item.price).toLocaleString()item.price.toLocaleString()으로 변경합니다.
      5. calcTotals 함수에서 Number(item.price)item.price로 변경합니다.
  3. Redux Slice (또는 Zustand Store) 내 합계 계산 로직을 증분 업데이트로 최적화하고, 파생된 상태를 Selector로 관리하세요.

    • 문제: increase, decrease, removeItem 액션마다 calcTotals가 전체 cartItems를 순회하며 amounttotal을 재계산합니다. amounttotalcartItems로부터 파생되는 값입니다.
    • 제안:
      • Zustand 사용 시: increase, decrease, removeItem 액션 내에서 amounttotal을 해당 아이템의 변화량만큼만 점진적으로 업데이트하도록 로직을 수정합니다.
      • Redux Toolkit 사용 시: CartState에서 amounttotal 필드를 제거하고, createSelector (reselect 라이브러리) 또는 일반 함수를 사용하여 cartItems로부터 totalAmounttotalPrice를 계산하는 selector를 정의하여 Homepage.tsx 등에서 사용하도록 합니다. 모든 리듀서에서 amounttotal을 직접 업데이트하는 로직과 calculateTotals 리듀서를 제거합니다.
  4. Homepage 컴포넌트의 콜백 함수에 useCallback을 적용하여 불필요한 리렌더링을 방지하세요.

    • 문제: src/page/Homepage.tsx에서 CartListCartSummaryonIncrease, onDecrease, onClear 콜백 함수를 전달할 때 매 렌더링마다 새로운 함수 참조가 생성되어 자식 컴포넌트의 불필요한 리렌더링을 유발할 수 있습니다.
    • 제안: useCallback 훅을 사용하여 이들 함수가 dispatch (혹은 Zustand의 increase, decrease 함수) 의존성 하에 안정적인 참조를 갖도록 변경합니다. 또한, CartList 컴포넌트가 CartItem 컴포넌트로 item.idincrease/decrease 함수 자체를 받도록 변경하여 CartItem 내에서 onClick={() => onIncrease(item.id)} 형태로 호출하도록 합니다.
  5. useReducer 관련 파일에 Discriminated Union 패턴 및 현대적인 타입 네이밍을 적용하세요.

    • 문제: src/pages/UseReducerPage.tsxsrc/pages/UseReducerCompany.tsxIAction 인터페이스에서 payload 정의가 모호하며, I 또는 T 접두사 사용은 현대 TypeScript 컨벤션에 맞지 않습니다.
    • 제안: 각 액션 type에 따라 필요한 payload를 명확히 정의하는 Discriminated Union 패턴을 사용하고, IState, IAction, TActionType 대신 State, Action, ActionType과 같이 직관적인 이름을 사용하세요.
  6. ClearCartModal의 버튼 구조 및 접근성을 강화하세요.

    • 문제: src/component/ClearCartModal.tsx에서 "네" 버튼과 "아니요" 버튼의 DOM 구조가 달라 시각적으로 일관성이 떨어지며, 모달의 기본적인 접근성 고려사항이 부족합니다.
    • 제안: 두 버튼을 하나의 div로 묶어 일관된 레이아웃을 적용하고, 모달 루트 divrole="dialog", aria-modal="true"를 추가하며, 포커스 관리 및 Escape 키 닫기 기능을 구현하여 접근성을 향상시키세요.
  7. CartItem 타입 정의를 중앙화하고 일관성 있게 관리하세요.

    • 문제: CartItem 타입 정의가 여러 곳에서 중복되거나 모호하게 참조되고 있습니다.
    • 제안: src/constants/cartItems.ts에서 실제 데이터의 타입을 추론하여 src/types/cart.ts (새로 생성하거나 기존 파일 활용)에 CartItem 타입을 중앙 집중화하여 정의하고, 이 타입이 필요한 모든 컴포넌트와 스토어 파일에서 import { CartItem } from '../types/cart';와 같이 가져와 사용합니다.
  8. 코드 품질 개선 (주석, console.log, 스타일링)

    • 문제: 디버깅용 console.log가 남아있고, 불필요한 중복 주석이 있으며, Navbarh-25UseReducerCompanyfont-2xl 같은 유효하지 않은 Tailwind 클래스가 사용되었습니다.
    • 제안:
      • 모든 console.log와 주석 처리된 코드를 제거합니다.
      • src/component/CartItem.tsx, src/component/ClearCartModal.tsx, src/store/useCartStore.ts, src/store/useModalStore.ts 등의 파일 상단에 있는 중복되거나 불필요한 주석을 제거합니다.
      • src/component/Navbar.tsxh-25를 유효한 Tailwind 클래스(예: h-24, h-28)나 Arbitrary value로 수정합니다.
      • src/pages/UseReducerCompany.tsxfont-2xltext-2xl로 수정합니다.

전반적으로 기능 구현은 잘 되어 있지만, 상태 관리 시스템의 통일은 가장 시급하고 중요한 개선점입니다. 위에서 제시된 제안들을 통해 코드의 견고성, 가독성, 유지보수성, 타입 안정성 및 사용자 경험을 더욱 향상시킬 수 있을 것입니다.

고생 많으셨습니다!

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.

9주차도 고생하셨습니다

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