Skip to content

Conversation

@guieuna3-lab
Copy link
Collaborator

📝 미션 번호

9주차 Misson 0, 1, 2, 3

📋 구현 사항

  • useReducer, redux(toolkits), Zustand를 이용한 장바구니 페이지 구현

📎 스크린샷

2025-12-14.133058.mp4
2025-12-14.172003.mp4
2025-12-14.205009.mp4
2025-12-14.202948.mp4

✅ 체크리스트

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

🤔 질문 사항

x

@guieuna3-lab guieuna3-lab self-assigned this Dec 14, 2025
@github-actions
Copy link

🤖 Gemini 코드리뷰 결과

안녕하세요, 시니어 프론트엔드 개발자로서 제출해주신 Pull Request의 변경사항을 면밀히 검토했습니다.

전반적으로 React, TypeScript, 그리고 Redux Toolkit 또는 Zustand와 같은 상태 관리 라이브러리를 활용하여 깔끔하게 기능을 구현하셨습니다. 특히 TypeScript를 사용하여 타입 안정성을 확보하고, Redux Toolkit의 createSlice나 Zustand의 immer 미들웨어를 효과적으로 사용한 점은 매우 긍정적입니다. Tailwind CSS를 적절히 활용하여 UI를 구성한 점도 좋습니다.

몇 가지 개선할 수 있는 부분들이 보이며, 주로 개발 환경 설정, 코드 가독성, 유지보수성, 성능 최적화, 사용자 경험 및 베스트 프랙티스와 관련된 제안입니다. 이 리뷰가 코드 품질 향상에 도움이 되기를 바랍니다.


PR 통합 리뷰 요약 및 구체적 개선 제안

리뷰는 크게 프로젝트 설정, 일반적인 React 및 UX 개선 사항, 그리고 상태 관리 라이브러리별 (Redux Toolkit, Zustand, useReducer) 구체적인 코드 개선 사항으로 나누어 진행됩니다.


I. 프로젝트 설정 및 개발 환경 개선 사항

주로 .gitignore, README.md, eslint.config.js, index.html, package.json 등 초기 설정 파일들을 검토했습니다.

  1. ESLint parserOptions.project 및 타입 기반 규칙 설정 (eslint.config.js)

    • 문제점: eslint.config.jsparserOptions.project 설정이 누락되어 있어 TypeScript 타입 정보를 활용한 고급 린팅(tseslint.configs.recommendedTypeChecked 등)이 제대로 작동하지 않습니다. 현재는 tseslint.configs.recommended만 사용 중입니다.
    • 개선 제안: languageOptions 내부에 parserOptions.project를 추가하고, extendstseslint.configs.recommendedTypeChecked 또는 더 엄격한 규칙을 활성화하여 타입스크립트의 장점을 최대한 활용하고 잠재적 런타임 오류를 줄일 수 있습니다.
      export default defineConfig([
        globalIgnores(['dist']),
        {
          files: ['**/*.{ts,tsx}'],
          extends: [
            // ... 기존 extends
            tseslint.configs.recommendedTypeChecked, // 변경 및 추가
            // optionally: tseslint.configs.strictTypeChecked,
            // optionally: tseslint.configs.stylisticTypeChecked,
            // React 전용 플러그인 추가 예시
            reactX.configs['recommended-typescript'],
            reactDom.configs.recommended,
          ],
          languageOptions: {
            ecmaVersion: 'latest', // 아래 제안과 함께 'latest'로 변경 권장
            sourceType: 'module',
            globals: globals.browser,
            parserOptions: {
              project: ['./tsconfig.json', './tsconfig.node.json'], // 또는 프로젝트에 맞는 경로
              tsconfigRootDir: import.meta.dirname, // ESLint 설정 파일 기준 경로
            },
          },
        },
      ]);
    • package.jsoneslint-plugin-react-x, eslint-plugin-react-domdevDependencies로 추가해야 합니다.
  2. 프로젝트명 "misson01" 오타 수정 ("mission01")

    • index.html<title> 태그와 package.jsonname, 그리고 전체 프로젝트 폴더명 misson01에 "mission" 오타가 있습니다.
    • 개선 제안: 이를 "mission01"로 일관성 있게 수정하여 혼란을 방지하고 프로젝트의 전문성을 높입니다.
  3. ESLint ecmaVersion 업데이트 (eslint.config.js)

    • eslint.config.js에서 ecmaVersion: 2020으로 설정되어 있습니다. 최신 React 및 Vite 환경에서는 최신 JavaScript 문법을 지원하기 위해 ecmaVersion: 'latest'로 업데이트하는 것이 좋습니다.
  4. Vite React 플러그인 SWC 버전 고려 (package.json)

    • 현재 @vitejs/plugin-react (Babel 기반)가 사용되고 있습니다. @vitejs/plugin-react-swc는 일반적으로 Babel 기반보다 더 빠른 HMR(Hot Module Replacement)과 빌드 성능을 제공합니다.
    • 개선 제안: 프로젝트 규모가 커지거나 빌드 성능이 중요해질 경우, plugin-react-swc로 전환하는 것을 고려해볼 수 있습니다. (package.json 변경 및 vite.config.ts 설정 필요)

II. 일반적인 React 및 사용자 경험 개선 사항

이 섹션의 제안들은 상태 관리 라이브러리에 관계없이 공통적으로 적용될 수 있는 내용입니다.

  1. 클라이언트 사이드 라우팅 사용 (Navbar.tsx 등)

    • 문제점: h1 태그의 onClick 핸들러나 다른 곳에서 window.location.href = '/'와 같이 직접적인 브라우저 API 호출을 사용하여 페이지를 새로고침하고 있습니다. 이는 SPA(Single Page Application)의 이점을 활용하지 못하고, 불필요한 리소스 로딩을 유발하여 성능과 사용자 경험에 부정적인 영향을 줄 수 있습니다.
    • 개선 제안: react-router-dom과 같은 클라이언트 사이드 라우팅 라이브러리를 도입하여 Link 컴포넌트나 useNavigate 훅을 사용해 페이지를 이동하는 것이 좋습니다. 이를 통해 부드러운 전환과 최적화된 리소스 관리가 가능합니다.
      // src/components/Navbar.tsx 예시 (react-router-dom 설치 및 BrowserRouter 설정 후)
      import { useNavigate } from "react-router-dom"; // 상단에 추가
      
      const Navbar = () => {
        // ...
        const navigate = useNavigate(); // useNavigate 훅 사용
      
        const handleNavigateToHome = () => {
          navigate('/'); // 클라이언트 사이드 라우팅
        };
      
        return (
          <div className="...">
            <h1 onClick={handleNavigateToHome} className="...">MusicCartList</h1>
            {/* ... */}
          </div>
        );
      };
  2. 이미지 alt 텍스트 견고성 강화 (CartItem.tsx)

    • 문제점: alt={${lp.title}의 LP 이미지}와 같이 lp.title에만 의존하는 alt 텍스트는 title이 없거나 비어 있을 경우 접근성 문제가 발생할 수 있습니다.
    • 개선 제안: nullish coalescing (??) 또는 logical OR (||) 연산자를 사용하여 대체 텍스트를 제공하여 접근성을 향상시킵니다.
      <img
        src={lp.img}
        alt={`${lp.title || '알 수 없는 앨범'}의 LP 이미지`} // 대체 텍스트 제공
        className="w-20 h-20 object-cover rounded mr-4"
      />
  3. 금액 표시 형식 개선 (가독성 및 사용자 경험)

    • 문제점: 25000 원과 같이 숫자로만 표시되는 금액은 큰 금액일 경우 가독성이 떨어질 수 있습니다.
    • 개선 제안: Intl.NumberFormat API를 사용하여 로컬라이즈된 통화 형식으로 금액을 표시하는 유틸리티 함수를 추가하면 가독성을 크게 향상시킬 수 있습니다.
      // src/utils/formatters.ts (새 파일 생성)
      export const formatCurrency = (amount: number, currency = 'KRW') => {
        return new Intl.NumberFormat('ko-KR', {
          style: 'currency',
          currency: currency,
          minimumFractionDigits: 0,
          maximumFractionDigits: 0,
        }).format(amount);
      };
      
      // src/components/CartItem.tsx 에서 사용 예시
      // <p className="text-sm font-bold text-gray-600">{formatCurrency(lp.price)}</p>
  4. 매직 스트링/넘버를 상수로 분리 (App.tsx, UseReducerCompany.tsx 등)

    • 문제점: "카드메이커", 에러 메시지, 리셋 후 부서명(UseReducerCompany.tsx), gap: 100 (App.tsx)와 같은 문자열이나 숫자가 코드 내에 하드코딩되어 있습니다. 이는 코드의 가독성, 유지보수성, 그리고 향후 다국어(i18n) 지원에 어려움을 줄 수 있습니다.
    • 개선 제안: 이러한 값들을 별도의 상수로 분리하여 관리합니다. 파일 상단이나 src/constants 폴더에 정의할 수 있습니다.
      // src/constants/ui.ts (예시)
      export const UI_SPACING_XL = '100px';
      export const DEFAULT_DEPARTMENT_TEXT = 'Department를 입력하세요';
      
      // src/App.css (CSS 변수 활용 예시)
      :root { --spacing-xl: 100px; }
      .app-container { gap: var(--spacing-xl); }
  5. Tailwind CSS 클래스 상수화 및 인라인 스타일 제거 (Modal.tsx, App.tsx)

    • 문제점: Modal.tsx의 모달 클래스들이 컴포넌트 내부에 직접 문자열로 명시되어 있고, App.tsx에는 인라인 스타일이 사용되었습니다. 이는 스타일의 재사용성을 낮추고 유지보수를 어렵게 할 수 있습니다.
    • 개선 제안: 반복되거나 재사용될 가능성이 있는 Tailwind CSS 클래스 조합은 별도의 상수 객체나 유틸리티 파일(예: src/styles/sharedStyles.ts)로 분리하고, App.tsx의 인라인 스타일은 CSS 클래스로 추출하여 App.css에 정의하는 것을 권장합니다.
      // src/styles/sharedStyles.ts
      export const MODAL_OVERLAY_CLASSES = "fixed inset-0 bg-white/50 backdrop-blur-sm flex items-center justify-center";
      export const PRIMARY_BUTTON_CLASSES = "px-4 py-2 bg-red-500 text-white rounded";
      
      // src/components/Modal.tsx 에서 사용
      // <div className={MODAL_OVERLAY_CLASSES}>...<button className={PRIMARY_BUTTON_CLASSES}>...</button></div>
  6. main.tsxdocument.getElementById('root')에 대한 안전한 접근

    • 문제점: document.getElementById('root')!에서 사용된 non-null assertion operator (!)는 root 요소가 항상 존재한다고 가정합니다. 이는 개발 환경에서는 문제가 없지만, 프로덕션 코드에서는 잠재적인 런타임 오류 가능성을 내포합니다.
    • 개선 제안: root 요소의 존재 여부를 명시적으로 확인하고 처리하는 안전한 접근 방식을 사용하는 것이 좋습니다.
      const rootElement = document.getElementById('root');
      if (rootElement) {
        createRoot(rootElement).render(
          <StrictMode>
            <App />
          </StrictMode>,
        );
      } else {
        console.error('Root element not found. Please ensure an element with id "root" exists in your index.html.');
        // 또는 적절한 오류 처리 로직
      }
  7. src/constants/cartItems.ts 파일 끝에 개행 문자 추가

    • 문제점: cartItems.ts 파일의 끝에 개행 문자(newline at end of file)가 없습니다. 이는 일부 개발 도구에서 문제를 일으킬 수 있으며, 일반적으로 권장되는 코드 스타일입니다.
    • 개선 제안: 파일 마지막 줄에 개행 문자를 추가합니다. 이는 Prettier 같은 포매터를 사용하면 자동화할 수 있습니다.
  8. 프로젝트 구조 개선 (선택 사항 - Barrel File)

    • 컴포넌트나 훅이 많아질 경우, 해당 디렉토리에 index.ts (barrel file)를 생성하여 컴포넌트들을 한 번에 export/import 할 수 있도록 설정하면 좋습니다.
    • 예시: src/components/index.tsexport { default as CartItem } from './CartItem'; 등으로 구성하면, import { CartItem, CartList } from "./components";와 같이 코드를 깔끔하게 유지할 수 있습니다.

III. 타입 및 데이터 구조 개선 사항

  1. Lp 타입/변수명 명확화 (src/types/cart.ts, src/components/CartItem.tsx)

    • 문제점: Lp라는 타입/변수명은 'Long Play' 레코드의 약어로 보이지만, 모든 개발자가 즉각적으로 이해하기 어렵고, 향후 카트 아이템 종류가 확장될 경우 혼란을 줄 수 있습니다.
    • 개선 제안: 도메인을 더 명확히 나타내는 CartItemData 또는 일반적인 ProductItem 등으로 변경하는 것이 좋습니다.
      // src/types/cart.ts
      export type CartItemData = { // Lp -> CartItemData
          id: string; title: string; singer: string; price:number; img: string; amount: number;
      }
      export type CartItems = CartItemData[] // Lp[] -> CartItemData[]
      이후 CartItem.tsx 등에서 lp 대신 item이나 cartItem으로 변경하여 사용합니다.
      // src/components/CartItem.tsx
      interface CartItemProps { item: CartItemData; } // lp -> item
      const CartItem = ({ item }: CartItemProps) => { /* ... item.id, item.amount 등 사용 */ }
  2. 상수 배열 타입 명시 및 불변성 강화 (src/constants/cartItems.ts, src/types/cart.ts)

    • 문제점: cartItems 배열이 명시적인 타입 없이 추론되고, CartItems 타입이 가변 배열(Lp[])로 정의되어 있습니다.
    • 개선 제안: cartItemsCartItems 타입을 명시적으로 지정하고, CartItems 타입을 readonly Lp[] 또는 readonly CartItemData[]로 변경하여 불변성 원칙을 강화합니다.
      // src/types/cart.ts
      export type CartItems = readonly CartItemData[]; // 불변성 강화
      
      // src/constants/cartItems.ts
      import type { CartItems } from "../types/cart";
      const cartItems: CartItems = [ /* ... */ ];
      export default cartItems;
  3. 컴포넌트 Props 구조 분해 할당 (src/components/CartItem.tsx)

    • 문제점: CartItem 컴포넌트에서 lp 객체 전체를 props로 받아 사용하고 있습니다.
    • 개선 제안: lp 객체 전체를 전달하기보다는 필요한 속성들만 구조 분해 할당으로 직접 받아 사용하는 것이 가독성과 재사용성을 높일 수 있습니다. (예: ({ item: { id, img, title, singer, price, amount } }: CartItemProps) => { ... })

IV. Redux Toolkit 상태 관리 개선 사항

주로 src/slices/cartSlice.ts 및 관련 컴포넌트를 검토했습니다.

  1. 초기 amounttotal 상태 계산 개선 (src/slices/cartSlice.ts)

    • 문제점: cartSliceinitialState에서 cartItems는 초기 데이터로 채워져 있지만, amounttotal0으로 초기화되어 있습니다. 이로 인해 초기 로딩 시 NavbaruseEffect가 실행되기 전까지 잠시 동안 0으로 표시될 수 있습니다.
    • 개선 제안: initialState를 정의할 때 cartItems를 기반으로 amounttotal을 즉시 계산하여 초기 상태의 일관성을 유지하고 useEffect에 대한 의존성을 줄입니다.
      const calculateTotalsFromItems = (items: CartItems) => {
        let amount = 0; let total = 0;
        items.forEach((item) => { amount += item.amount; total += item.amount * item.price; });
        return { amount, total };
      };
      const { amount: initialAmount, total: initialTotal } = calculateTotalsFromItems(cartItems);
      
      const initialState: CartState = {
        cartItems,
        amount: initialAmount,
        total: initialTotal,
      };
  2. decrease 리듀서 로직 중앙화 및 리팩토링 (src/slices/cartSlice.ts, src/components/CartItem.tsx)

    • 문제점: CartItem.tsx 컴포넌트에서 "수량이 1일 때 removeItem 디스패치"하는 조건부 로직을 가지고 있습니다. 이는 장바구니 아이템을 줄이는 로직이 컴포넌트와 리듀서에 분산되어 있음을 의미합니다.
    • 개선 제안: "수량이 0 이하가 되면 아이템을 제거"하는 로직을 decrease 리듀서 내부로 옮겨, 상태 변경 로직의 단일 책임 원칙을 강화하고 컴포넌트를 더 단순하게 만듭니다.
      // src/slices/cartSlice.ts
      decrease: (state, action: PayloadAction<{ id: string }>) => {
        const item = state.cartItems.find((cartItem) => cartItem.id === action.payload.id);
        if (item) {
          item.amount -= 1;
          if (item.amount <= 0) {
            state.cartItems = state.cartItems.filter((cartItem) => cartItem.id !== action.payload.id);
          }
        }
      },
      CartItem.tsxhandleDecreaseCount에서는 단순히 dispatch(decrease({ id: lp.id }))만 호출하면 됩니다.
  3. Redux cartSlice 내 중복 로직 추상화 (findItemById) (src/slices/cartSlice.ts)

    • 문제점: increasedecrease 리듀서에서 동일하게 state.cartItems.find(...) 로직을 사용하여 카트 아이템을 찾고 있습니다.
    • 개선 제안: 반복되는 아이템 검색 로직을 별도의 헬퍼 함수로 추출하여 추상화하면 코드가 더 간결해지고 DRY(Don't Repeat Yourself) 원칙을 따를 수 있습니다.
      const findItemById = (state: CartState, id: string) => {
        return state.cartItems.find((cartItem) => cartItem.id === id);
      };
      
      const cartSlice = createSlice({
        name: "cart", initialState, reducers: {
          increase: (state, action) => { const item = findItemById(state, action.payload.id); if (item) item.amount += 1; },
          decrease: (state, action) => { const item = findItemById(state, action.payload.id); if (item) item.amount -= 1; },
          // ...
        },
      });
  4. 함수명 오타 수정 및 의미 명확화 (src/components/PriceBox.tsx)

    • 문제점: PriceBox.tsx 컴포넌트의 handleInitiallize 함수명에 오타(Initiallize -> Initialize)가 있습니다. 또한, 이 함수가 수행하는 실제 작업은 "카트 비우기"이므로, handleClearCart와 같이 더 명확한 이름으로 변경하는 것이 좋습니다.
    • 개선 제안: 오타를 수정하고, 함수의 의도를 더 잘 나타내는 이름으로 변경하여 코드의 가독성을 높입니다.
  5. useEffect 의존성 배열에 dispatch 포함 사유 주석 추가 (src/components/Navbar.tsx)

    • 문제점: Navbar.tsxuseEffect 훅에 dispatch가 의존성 배열에 포함되어 있습니다. Redux Toolkit의 useDispatch는 안정적인 함수이므로 의존성 배열에 포함할 필요가 없다고 오해할 수 있습니다.
    • 개선 제안: dispatch가 안정적임에도 불구하고 ESLint의 exhaustive-deps 규칙을 만족시키기 위해 포함되었다는 주석을 추가하여 코드의 의도를 명확히 합니다.
      useEffect(() => {
        dispatch(calculateTotals())
      }, [cartItems, dispatch]) // `dispatch`는 안정적인 함수이지만, ESLint의 `exhaustive-deps` 규칙을 만족시키기 위해 포함됩니다.

V. Zustand 상태 관리 개선 사항

주로 src/stores/counterStore.ts, src/hooks/useCartStore.ts 및 관련 컴포넌트를 검토했습니다.

  1. useCallback으로 이벤트 핸들러 최적화 (src/components/CartItem.tsx, src/components/CounterButton.tsx)

    • 문제점: handleIncreaseCounthandleDecreaseCount 함수가 컴포넌트가 렌더링될 때마다 새로 생성됩니다. 이는 컴포넌트가 React.memo 등으로 최적화될 경우 불필요한 리렌더링을 유발할 수 있습니다.
    • 개선 제안: useCallback으로 감싸서 불필요한 함수 재생성을 방지하고 잠재적인 성능 최적화 기반을 마련합니다.
      const handleIncreaseCount = useCallback(() => {
        increase(id); // id는 props에서 구조 분해 할당된 값
      }, [increase, id]);
      
      const handleDecreaseCount = useCallback(() => {
        if (amount === 1) { // amount도 props에서 구조 분해 할당된 값
          removeItem(id);
          return;
        }
        decrease(id);
      }, [decrease, removeItem, id, amount]);
  2. useShallow 선택자 개선 (src/components/Counter.tsx)

    • 문제점: Counter.tsx에서는 count만 사용하지만, useShallow를 통해 incrementdecrement 액션도 선택하고 있습니다. 액션은 CounterButton으로 분리하여 useCounterActions를 통해 주입되고 있습니다.
    • 개선 제안: Counter.tsx에서는 count 값만 선택하도록 useShallow 콜백을 변경하여 불필요한 액션 선택을 제거합니다.
      // After
      const { count } = useCounterStore(
        useShallow((state) => ({
          count: state.count,
        }))
      );
      // 또는, count만 필요하다면 useShallow 없이 직접 가져와도 무방합니다:
      // const count = useCounterStore((state) => state.count);
  3. Zustand set 함수 콜백 반환 타입 및 replace 인자 명시 제거 (src/stores/counterStore.ts)

    • 문제점: set 함수 내부의 콜백 함수에서 반환 타입을 명시하는 부분((state): { count: number } => ...)과 replace 인자 false는 불필요합니다.
    • 개선 제안: TypeScript가 자동으로 추론할 수 있는 반환 타입 명시는 제거하고, replace 인자 false는 기본값이므로 생략하여 코드를 더 간결하게 만듭니다.
      // Before (예시)
      set((state): { count: number } => ({ count: state.count + 1 }), false, "increment");
      
      // After
      set((state) => ({ count: state.count + 1 }), "increment"); // replace 인자 'false' 생략
  4. Zustand create 함수 get 인자 명시 (src/hooks/useCartStore.ts)

    • 문제점: useCartStore에서 set 함수 콜백의 두 번째 인자인 _ (get)이 사용되지 않거나, immer 미들웨어는 get 함수를 제공하지만 _로 처리되어 있습니다.
    • 개선 제안: set 함수 콜백에서 get 인자를 사용하지 않는다면 _로 두는 것은 무방하나, 사용한다면 명시적으로 get으로 이름을 지정하여 가독성을 높일 수 있습니다.
      export const useCartStore = create<CartState>()(
        immer((set, get) => ({ // _ 대신 get으로 명시하여 가독성 향상
          // ...
        }))
      );

VI. useReduceruseState 예제 개선 사항

주로 src/UseReducerCompany.tsx 파일을 검토했습니다.

  1. IAction 타입 정밀화 (Discriminated Unions)

    • 문제점: IAction 인터페이스가 payload?: string;으로 정의되어 있어, payload가 필요 없는 액션에도 전달할 수 있고, 필요한 액션에서도 undefined 타입 처리 로직이 필요할 수 있습니다.
    • 개선 제안: 액션 타입에 따라 payload 유무와 타입을 명확히 하는 discriminated union을 사용하여 더 견고한 타입 안전성을 확보합니다.
      interface ChangeDepartmentAction { type: "CHANGE_DEPARTMENT"; payload: string; }
      interface ResetAction { type: "RESET"; } // payload가 필요 없음
      type IAction = ChangeDepartmentAction | ResetAction;
  2. RESET 액션 시 error 상태 초기화 및 의도 명확화

    • 문제점: RESET 액션 시 department만 변경되고 error 상태는 초기화되지 않으며, 초기 상태("Software Developer") 대신 다른 문자열("Department를 입력하세요")로 리셋됩니다.
    • 개선 제안: RESET 액션 처리 시 department와 함께 errornull로 초기화하여 깨끗한 상태를 유지합니다. 또한 RESET 액션의 의도를 명확히 합니다 (완전 초기화 또는 특정 플레이스홀더 텍스트로 초기화). 완전 초기화를 원한다면 useReducerinitialState를 상수로 정의하고 이를 반환합니다.
      const INITIAL_COMPANY_STATE: IState = { department: "Software Developer", error: null };
      // ...
      case "RESET": {
        return { ...INITIAL_COMPANY_STATE }; // 원본 초기 상태로 복원
      }
  3. 유효하지 않은 입력에 대한 UI 피드백 강화

    • 문제점: 유효하지 않은 부서명을 입력했을 때 에러 메시지는 표시되지만, 입력 필드 자체에는 시각적인 변화가 없어 사용자에게 즉각적인 피드백을 주기 어렵습니다.
    • 개선 제안: state.error가 있을 때 입력 필드에 에러 스타일(예: 빨간색 테두리)을 적용하여 사용자 경험을 개선합니다.
      <input
        className={`w-[330px] border mt-10 p-4 rounded-md ${state.error ? 'border-red-500' : ''}`}
        placeholder="변경하고 싶은 직무 입력 (거부권 행사 가능)"
        value={department}
        onChange={handleChangeDepartment}
      />
  4. 직무 변경 후 입력 필드 자동 초기화

    • 문제점: "직무 변경하기" 버튼을 눌러 상태를 업데이트한 후에도 입력 필드의 텍스트가 그대로 남아 있어, 사용자가 다음 입력을 위해 직접 지워야 합니다.
    • 개선 제안: 직무 변경 시도 후 (성공 여부와 관계없이), setDepartment("")를 호출하여 입력 필드를 초기화합니다.
      <button
        onClick={() => {
          dispatch({ type: "CHANGE_DEPARTMENT", payload: department });
          setDepartment(""); // 디스패치 후 입력 필드 초기화
        }}
      >
        직무 변경하기
      </button>
  5. Tailwind CSS font-2xl 클래스 수정

    • 문제점: 에러 메시지에 <p className="text-red-500 font-2xl">{state.error}</p>와 같이 font-2xl 클래스가 사용되었습니다. Tailwind CSS에서 폰트 크기 유틸리티는 text-2xl 형태로 제공됩니다.
    • 개선 제안: font-2xl을 올바른 text-2xl로 변경하여 예상대로 폰트 크기를 적용합니다.

총평

제시해주신 코드는 Redux Toolkit, Zustand, React Hooks의 기본적인 컨벤션과 모범 사례를 잘 따르고 있으며, TypeScript 활용 능력이 뛰어납니다. useCustomRedux 훅을 통해 타입 안정성을 확보하려는 노력과 zustand/shallow 사용 등은 칭찬할 만합니다.

위의 제안들은 대부분 코드의 가독성, 유지보수성, 확장성 그리고 사용자 경험을 더욱 개선하기 위한 추가적인 고려사항들입니다. 이를 통해 프로젝트의 전반적인 품질을 한층 더 높일 수 있을 것입니다.

궁금한 점이 있다면 언제든지 질문해주세요. 고생 많으셨습니다!

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.

3 participants