Skip to content

Create Week8 Mission1,2,3#113

Merged
huheyun merged 2 commits intomainfrom
gureum/week08
Dec 16, 2025
Merged

Create Week8 Mission1,2,3#113
huheyun merged 2 commits intomainfrom
gureum/week08

Conversation

@huheyun
Copy link
Copy Markdown
Contributor

@huheyun huheyun commented Nov 25, 2025

📝 미션 번호

8주차 Misson 1,2,3

📋 구현 사항

  • Debounce 활용하여 불필요한 호출 막기
  • Throttle 사용하여 불필요한 호출 막기
  • sidebar 리팩토링하기

📎 스크린샷

2025-11-25.022319.mp4
2025-11-25.023118.mp4
2025-11-25.025618.mp4

✅ 체크리스트

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

🤔 질문 사항

@huheyun huheyun requested a review from woojo230 November 25, 2025 04:08
@huheyun huheyun self-assigned this Nov 25, 2025
@github-actions
Copy link
Copy Markdown

🤖 Gemini 코드리뷰 결과

안녕하세요, 시니어 프론트엔드 개발자로서 제공해주신 Pull Request 변경 사항을 면밀히 검토했습니다. 주로 src 디렉터리 내의 .ts.tsx 파일들을 중심으로 리뷰를 진행했으며, 파일별 상세 피드백과 함께 통합된 개선 제안을 드립니다. package.jsonpackage-lock.json과 같은 설정 및 의존성 파일에 대해서도 중요한 관찰 사항과 제안을 포함했습니다.


PR 리뷰 요약

이번 PR은 초기 프로젝트 설정 및 API 연동을 위한 견고한 기반을 잘 다지고 있습니다. 특히 react-query, react-hook-form, zod, Tailwind CSS 등 최신 기술 스택을 적절히 활용하여 데이터 관리, 폼 유효성 검사, 스타일링에 있어 좋은 접근 방식을 보여줍니다. Axios 인터셉터를 통한 토큰 관리 로직 및 무한 스크롤, 낙관적 업데이트와 같은 고급 기능 구현도 인상 깊습니다.

그러나 몇 가지 성능 최적화, 타입 안정성 강화, 코드 재사용성 및 유지보수성 향상, 그리고 사용자 경험 및 접근성 측면에서 개선할 점과 잠재적 이슈가 발견되었습니다. 아래에서 각 파일별 상세 리뷰와 더불어, 통합된 개선 제안을 드립니다.


1. 파일별 상세 리뷰 및 개선 제안

1.1. API 관련 파일

src/apis/axios.ts

  • 성능 문제 / 리팩토링 포인트:
    • Axios 인터셉터 내 디버깅 로직 및 atob 사용: JWT 토큰을 매 요청마다 디코딩(atob, JSON.parse)하고 콘솔 로그를 출력하는 부분이 있습니다. 이는 개발 단계에서는 유용하지만, 프로덕션 환경에서는 불필요한 연산 오버헤드를 발생시키고 성능에 영향을 줄 수 있으며, 사용자 콘솔에 민감한 정보가 노출될 위험이 있습니다.
    • 로컬 스토리지 토큰 파싱 로직 중복: localStorage에 저장된 토큰을 가져올 때, JSON 문자열 여부를 확인하고 파싱하는 로직이 요청 인터셉터와 refreshAccessToken 함수 내에서 중복됩니다.
  • 타입스크립트 문법 / 타입 개선점:
    • AxiosRequestConfig 타입 확장: 응답 인터셉터에서 originalRequest._retry = true와 같이 AxiosRequestConfig에 없는 속성 _retry를 추가하고 있습니다. 이는 타입 오류를 일으키거나 타입 안정성을 해칠 수 있습니다.
  • 보안 고려사항:
    • 토큰 저장 방식: accessTokenrefreshToken 모두 localStorage에 저장하고 있습니다. localStorage는 XSS(Cross-Site Scripting) 공격에 취약하여 저장된 토큰이 탈취될 위험이 있습니다.
  • 사용자 경험:
    • 토큰 갱신 실패 시 사용자 피드백: refreshAccessToken 실패 시 단순히 콘솔에 에러를 기록하고 /login으로 리다이렉션합니다. 사용자에게 세션 만료를 알리는 친화적인 메시지 없이 갑자기 로그인 페이지로 이동하는 것은 좋지 않은 경험을 제공합니다.
    • 다중 리디렉션 방지: 여러 개의 API 요청이 동시에 401 에러를 발생시킬 경우, 여러 번의 window.location.href = "/login" 리디렉션 시도가 발생할 수 있습니다.
  • 개선 제안:
    • 환경 변수 기반 디버그 로그 및 atob 비활성화: if (import.meta.env.DEV) 또는 process.env.NODE_ENV !== 'production'과 같은 조건문으로 console.logatob 연산을 감싸 프로덕션 빌드 시 비활성화합니다.
    • 토큰 파싱 유틸리티 함수 분리: getParsedToken(key: LOCAL_STORAGE_KEY)와 같은 유틸리티 함수를 추출하여 로컬 스토리지 토큰 파싱 로직의 중복을 제거하고 재사용성을 높입니다.
    • AxiosRequestConfig 타입 확장: axios 모듈을 확장하여 AxiosRequestConfig 인터페이스에 _retry?: boolean; 속성을 추가하여 타입 안전하게 사용합니다. (예: src/types/axios.d.ts 파일 생성)
    • 토큰 저장 보안 강화: refreshToken은 HTTP-only 쿠키에 저장하고, accessTokensessionStorage 또는 메모리에 유지하는 것을 고려합니다.
    • 사용자 친화적인 에러 메시지 및 단일 리다이렉션: 리다이렉션 전 사용자에게 세션 만료 알림(토스트 등)을 제공하고, isRedirectingToLogin과 같은 전역 플래그를 사용하여 리다이렉션 중복을 방지합니다. React Router의 navigate 함수를 사용하여 SPA 전환을 부드럽게 합니다.

src/apis/auth.ts

  • 타입스크립트 문법 / 타입 개선점:
    • postRefreshToken 함수와 src/apis/axios.tsrefreshAccessToken 함수에서 기대하는 API 응답 구조(response.data vs response.data.data)에 대한 타입 정의가 불분명하거나 일관되지 않을 수 있습니다.
  • 개선 제안: 백엔드 API의 실제 응답 구조를 확인하고, ResponseRefreshTokenDto 타입을 이에 맞춰 명확하게 정의하여 응답 타입 구조를 통일합니다.

src/apis/lp.ts

  • 중복 코드 및 리팩토링 포인트:
    • fetchLpList, fetchUserLpList, fetchMyLpList, fetchLpComments 등 여러 API 함수에서 URLSearchParams를 생성하고 쿼리 파라미터를 추가하는 로직이 매우 유사하게 반복됩니다.
  • 개선 제안: 파라미터 객체를 받아 쿼리 문자열을 반환하는 유틸리티 함수(예: buildQueryParams(params: Record<string, any>): string)를 만들어 중복 코드를 줄이고 응집도를 높여줍니다.

src/services/lpApi.ts

  • 평가: Deprecated 처리하고 apis/lp.ts에서 재익스포트하는 것은 의도된 리팩토링으로 보이며, 잘 처리되었습니다.
  • 개선 제안: 모든 코드에서 새 경로를 사용하도록 마이그레이션이 완료되면 이 파일을 제거하여 코드베이스를 간결하게 유지합니다.

1.2. 컴포넌트 관련 파일

src/components/Navbar.tsx

  • 성능 문제: getLoginButtonClasses, getSignupButtonClasses 함수가 렌더링 시마다 호출되지만, 내부 로직이 간단하여 성능에 미치는 영향은 미미합니다.
  • 변수명, 함수명, 주석 품질: active prop의 이름이 login 또는 signup 페이지를 나타내므로, activeAuthPage 등으로 더 구체화할 수 있습니다.
  • 중복 코드 및 리팩토링 포인트:
    • SVG 아이콘 중복: 검색 아이콘, 사용자 프로필 아이콘 (및 Sidebar.tsx의 홈 아이콘 등)이 인라인으로 존재하며 여러 컴포넌트에서 중복됩니다.
    • 인증 상태 UI 중복: "로그인 상태 환영 문구" 및 "로그인이 필요합니다" 섹션이 NavbarSidebar에서 거의 동일하게 구현되어 있습니다.
    • 로그아웃 버튼 로직/UI 중복: logoutMutation 관련 로직과 버튼 UI가 NavbarSidebar에서 중복됩니다.
  • 개선 제안:
    • 공통 UI 컴포넌트 추출: AuthStatusDisplay, LogoutButton, HomeIcon, SearchIcon 등과 같은 재사용 가능한 컴포넌트 및 아이콘 컴포넌트를 /src/components/icons 디렉터리 내에 분리하여 중복을 제거하고 재사용성을 높입니다.
    • NavbarPropsonToggleSidebar prop을 선택적(?)으로 변경하여, 사이드바가 없는 레이아웃에서는 이 prop을 생략할 수 있도록 합니다.

src/components/auth/GoogleLoginButton.tsx

  • 평가: GOOGLE_LOGIN_MESSAGESas const로 사용하여 타입 추론을 강화한 것은 좋은 예시입니다.
  • 개선 제안: 특이사항 없음.

src/components/comments/CommentForm.tsx

  • 타입스크립트 문법 / 타입 개선점: onSubmit prop의 타입이 (content: string) => void;로 되어 있습니다. 만약 댓글 제출이 비동기 작업이라면 Promise<void> 등으로 반환 타입을 명시하는 것이 좋습니다.
  • 중복 코드 및 리팩토링 포인트:
    • 인증 상태 로직 부재: "로그인 후 댓글을 작성할 수 있습니다."라는 메시지가 있지만, 실제 컴포넌트 자체는 로그인 상태를 알지 못하여 폼을 비활성화하지 않습니다.
    • 오류 메시지 UI: 오류 메시지에 사용된 SVG 아이콘이 인라인으로 존재합니다.
  • 개선 제안:
    • 인증 상태 기반 UI 제어: isAuthenticated: boolean prop을 추가하거나 useAuth 훅을 직접 사용하여, 로그인되지 않은 상태에서는 textarea와 제출 버튼을 disabled 처리하거나 댓글 작성 영역을 로그인 유도 메시지로 대체하여 사용자 경험을 개선합니다.
    • ErrorMessage 컴포넌트 분리: 오류 메시지와 SVG 아이콘을 재사용 가능한 ErrorMessage 컴포넌트로 분리합니다.

src/components/comments/CommentList.tsx

  • 성능 문제: useDebounceuseThrottle 훅을 사용하여 검색 및 무한 스크롤 성능을 최적화한 것은 매우 훌륭합니다. allComments.finddocument.addEventListener 내부 로직은 댓글 수가 매우 많아질 경우 미세한 성능 저하 가능성이 있습니다.
  • 타입스크립트 문법 / 타입 개선점: useMutationonError 콜백에서 error: any로 처리하는 부분이 여러 곳에서 보입니다. AxiosError와 같이 더 구체적인 에러 타입을 지정하면 타입 안정성을 높일 수 있습니다. initialPageParam: undefined as number | undefinedundefined로만 지정해도 충분합니다.
  • 중복 코드 및 리팩토링 포인트:
    • 댓글 입력 폼 중복: CommentForm.tsx가 이미 존재함에도 불구하고 CommentList.tsx 내부에 별도의 댓글 입력 폼이 다시 구현되어 있습니다.
    • 댓글 아이템 컴포넌트 분리: allComments.map 내부의 개별 댓글 렌더링 로직이 길고 복잡합니다.
    • SVG 아이콘 중복: 댓글 메뉴 및 수정/삭제 아이콘들이 인라인으로 존재합니다.
    • 에러 처리 로직 중복: createCommentMutation, updateCommentMutation, deleteCommentMutationonError 콜백에서 에러 메시지 추출 및 alert 로직이 반복됩니다.
    • formatDate 함수 중복: formatDate 함수가 LpCard.tsxLpDetailPage.tsx에도 유사하게 정의되어 있습니다.
  • 개선 제안:
    • CommentForm 재사용: 기존 CommentForm.tsx 컴포넌트를 재사용하여 댓글 입력 폼의 중복을 제거합니다.
    • CommentItem 컴포넌트 분리: 각 댓글을 CommentItem.tsx와 같은 별도의 컴포넌트로 분리하여 가독성과 관리 용이성을 높이고 editingCommentId 등의 상태를 CommentItem 내부에서 관리하도록 합니다.
    • 공통 아이콘 컴포넌트 분리: 인라인 SVG 아이콘들을 별도 컴포넌트로 분리합니다.
    • 에러 메시지 추출 유틸리티 함수 도입: getErrorMessage(error: unknown): string와 같은 유틸리티 함수를 만들어 에러 처리 로직의 중복을 제거합니다.
    • formatDate 유틸리티 함수로 추출: src/utils/date.ts와 같은 공통 유틸리티 파일로 formatDate 함수를 추출하여 재사용성을 높입니다.
    • useCallback 적용: handleSortToggle, handleSubmitComment 등 함수에 useCallback을 적용하여 불필요한 재렌더링을 방지합니다.

src/components/common/BurgerIcon.tsx, src/components/common/CommentListSkeleton.tsx, src/components/common/FloatingButton.tsx, src/components/common/FormInput.tsx, src/components/common/LoginButton.tsx, src/components/common/LoginRequiredModal.tsx, src/components/common/LpListSkeleton.tsx

  • 평가: 전반적으로 깔끔하고 잘 작성되었습니다. FloatingButtonvariantposition을 이용한 타입 안전성이 좋고, FormInput의 제네릭 타입 활용도 훌륭합니다. BurgerIcon은 접근성을 고려한 aria-label을 포함하여 좋습니다.
  • 개선 제안:
    • FloatingButton 아이콘 접근성: 버튼에 ariaLabel이 제공되므로 SVG 자체에는 aria-hidden="true"를 추가하여 스크린 리더가 중복해서 읽는 것을 방지합니다.
    • FormInput 오류 메시지 접근성: 오류 메시지 <p> 태그에 aria-live="assertive"를 추가하여 스크린 리더 사용자가 오류를 즉시 인지하도록 합니다.
    • LoginButton 에러 처리: handleSubmit의 에러를 catch하고 console.error만 하는 대신, 상위 컴포넌트가 에러를 처리할 수 있도록 재발생시키거나 콜백을 통해 전달하는 것을 고려합니다.
    • 모달 접근성 개선 (LoginRequiredModal): role="dialog", aria-modal="true", aria-labelledby, aria-describedby 속성을 추가하고, 모달이 열릴 때 내부에 초점을 가두고 ESC 키로 닫히도록 로직을 추가합니다.

src/components/common/LpCard.tsx

  • 중복 코드 및 리팩토링 포인트: formatDate 함수가 다른 파일과 중복됩니다. 좋아요 하트 SVG와 달력 SVG가 인라인으로 존재합니다.
  • 개선 제안:
    • formatDate 유틸리티 함수로 추출: src/utils/date.ts로 추출하여 재사용합니다.
    • 내비게이션 시맨틱스: 전체 divonClick을 사용하는 대신, react-router-domLink 컴포넌트를 사용하여 LP 상세 페이지로 이동하도록 구현하여 접근성을 개선합니다.
    • 공통 아이콘 컴포넌트 분리: 인라인 SVG 아이콘들을 별도 컴포넌트로 분리합니다.

src/components/layout/Sidebar.tsx

  • 타입스크립트 문법 / 타입 개선점: useMutationonError 콜백에서 error: any로 처리하는 부분이 보입니다.
  • 중복 코드 및 리팩토링 포인트:
    • Navbar.tsx와 중복: "SVG 아이콘 중복", "인증 상태 UI 중복", "로그아웃 버튼 로직/UI 중복" 문제가 Sidebar.tsx에서도 동일하게 나타납니다.
    • 에러 처리 로직 중복: logoutMutation, deleteUserMutationonError에서 에러 메시지 추출 및 alert 로직이 반복됩니다.
    • window.innerWidth < 768 중복: 모바일 화면 여부를 체크하는 로직이 여러 곳에서 반복됩니다.
    • 회원 탈퇴 후 localStorage 직접 조작: deleteUserMutation.onSuccess에서 localStorage.removeItem을 직접 호출하고 window.location.reload()를 하는 대신, useAuth 훅의 logout 함수를 호출하여 인증 컨텍스트의 상태를 일관되게 초기화하는 것이 좋습니다.
  • 개선 제안:
    • 공통 UI 컴포넌트 활용: Navbar.tsx에서 제안된 AuthStatusDisplay, LogoutButton, 아이콘 컴포넌트를 사용합니다.
    • 에러 메시지 추출 유틸리티 함수 적용: getErrorMessage 함수를 적용합니다.
    • useIsMobile 커스텀 훅 도입: window.innerWidth 기반 로직을 추상화하는 커스텀 훅을 만들어서 사용합니다.
    • useAuthlogout 함수 활용: 회원 탈퇴 성공 시 logout() 함수를 호출하여 인증 상태 관리를 일관되게 합니다.

src/components/lps/CreateLpModal.tsx

  • 타입스크립트 문법 / 타입 개선점: error: any 타입이 사용되고 있습니다.
  • 중복 코드 및 리팩토링 포인트:
    • 모달 접근성 개선: LoginRequiredModal과 마찬가지로 이 모달도 접근성을 위한 role="dialog", aria-modal="true", aria-labelledby 등을 추가해야 합니다.
    • SVG 아이콘 중복: 닫기 버튼 SVG와 LP 이미지 플레이스홀더 SVG가 인라인으로 존재합니다.
    • 에러 처리 로직 중복: uploadImageMutation, createLpMutation, updateLpMutationonError에서 에러 메시지 처리가 반복됩니다.
    • 플레이스홀더 이미지 URL: https://via.placeholder.com/400과 같은 문자열이 직접 사용되고 있습니다.
  • 개선 제안:
    • 모달 접근성 강화: role, aria 속성 추가 및 초점(focus) 관리 로직을 구현합니다.
    • 공통 아이콘 컴포넌트 분리: 인라인 SVG 아이콘들을 별도 컴포넌트로 분리합니다.
    • 에러 메시지 추출 유틸리티 함수 적용: getErrorMessage 함수를 적용합니다.
    • 플레이스홀더 이미지 URL 상수화: DEFAULT_LP_THUMBNAIL과 같은 상수로 정의하여 관리합니다.
    • 이미지 업로드 피드백 강화: 이미지 선택 영역 자체에 로딩 스피너 등을 표시하여 사용자에게 더 명확한 피드백을 제공합니다.
    • 폼 유효성 검사 강화: useForm 훅과 연동하여 각 필드에 대한 구체적인 클라이언트 측 유효성 검사를 구현합니다.
    • 태그 입력 UX 개선: 태그 추가 후 입력 필드에 자동으로 포커스를 재설정하여 연속적인 태그 입력을 편리하게 만듭니다.

src/components/lps/LpList.tsx

  • 타입스크립트 문법 / 타입 개선점: error: any 타입이 사용되고 있습니다. initialPageParam: undefined as number | undefined는 불필요한 타입 단언을 제거할 수 있습니다.
  • 중복 코드 및 리팩토링 포인트: isError 블록의 JSX 구조가 CommentList.tsx의 에러 처리 UI와 매우 유사합니다.
  • 개선 제안:
    • 에러 메시지 추출 유틸리티 함수 적용: getErrorMessage 함수를 적용합니다.
    • ErrorRetryMessage 공통 컴포넌트 도입: CommentList.tsxLpList.tsx의 반복되는 에러 및 재시도 UI를 ErrorRetryMessage.tsx와 같은 공통 컴포넌트로 분리하여 재사용성을 높입니다.

1.3. 상수 및 컨텍스트, 훅 관련 파일

src/constants/key.ts

  • 평가: LOCAL_STORAGE_KEYS as const는 타입 안전성을 높이는 좋은 방법입니다.
  • 중복 코드 및 리팩토링 포인트: LOCAL_STORAGE_KEY = LOCAL_STORAGE_KEYS;는 이전 코드와의 호환성을 위한 것이겠지만, 점진적으로 제거하고 LOCAL_STORAGE_KEYS만 사용하도록 유도하는 것이 좋습니다.
  • 개선 제안: LOCAL_STORAGE_KEY@deprecated JSDoc 태그를 추가하여 IDE에서 사용 시 경고를 표시하고, 모든 코드에서 LOCAL_STORAGE_KEYS (복수형)를 사용하도록 마이그레이션이 완료되면 해당 상수를 제거합니다.

src/context/AuthContext.tsx

  • 평가: AuthContextType 인터페이스가 잘 정의되어 있으며, login 함수가 Promise<boolean>을 반환하도록 명시하여 비동기 작업의 성공/실패 여부를 명확히 한 것은 좋습니다.
  • 개선 제안: 특이사항 없음.

src/hooks/useAuth.ts

  • 평가: 컨텍스트 사용을 위한 표준적인 커스텀 훅입니다. useContext를 올바르게 사용하고 null 체크를 통해 에러를 발생시키는 것은 좋은 패턴입니다.
  • 개선 제안: 특이사항 없음.

src/hooks/useDebounce.ts, src/hooks/useThrottle.ts

  • 평가: 디바운스 및 쓰로틀링 로직이 효율적으로 구현되어 불필요한 함수 호출을 줄입니다. 제네릭 <T>를 사용하여 값의 타입을 유연하게 처리하고, JSDoc에 상세한 타입 정보와 예시를 제공한 것은 매우 훌륭합니다.
  • 개선 제안: 특이사항 없음.

src/hooks/useForm.ts

  • 평가: 제네릭 <T extends Record<string, any>>를 사용하여 폼 값의 타입을 안전하게 관리하며, initialValue prop을 @deprecated로 표시한 것은 좋은 개발 관행입니다. validate 함수의 타입 정의도 견고합니다.
  • 타입스크립트 문법 / 타입 개선점: handleFieldChange에서 value가 항상 string이라고 가정하고 있습니다. type="number"와 같은 입력 필드를 사용할 경우를 고려하여 value: any로 하거나 handleFieldChange를 오버로드하는 방식을 고려할 수 있습니다.
  • 개선 제안: 특이사항 없음 (현재 사용처에는 string으로 충분).

src/hooks/useLocalStorage.ts

  • 평가: 이 파일은 use 접두사를 사용하지만 실제 React Hook의 규칙(useState, useEffect 등을 사용)을 따르지 않고 있습니다. AuthProvider에서 localStorage를 직접 다루는 유틸리티 함수로 사용되고 있기 때문으로 보입니다.
  • 타입스크립트 문법 / 타입 개선점: getItem()은 현재 any를 반환합니다. 제네릭을 사용하여 호출하는 쪽에서 타입을 명시할 수 있도록 개선할 수 있습니다.
  • 변수명, 함수명, 주석 품질: useLocalStorage라는 이름은 표준 React Hook으로 오해될 수 있습니다.
  • 개선 제안:
    • 이름 변경 및 제네릭 타입 추가: createLocalStorageManager 등으로 이름을 변경하고, getItem 함수에 제네릭 타입을 추가하여 반환 값의 타입 안정성을 높입니다. (예: src/utils/localStorage.ts로 이동)

src/hooks/useSidebar.ts

  • 성능 문제: useState, useEffect, useCallback을 사용하여 불필요한 렌더링을 방지하고 사이드 이펙트를 효율적으로 관리합니다.
  • 접근성 개선: 사이드바가 열렸을 때 메인 콘텐츠 영역에 aria-hidden="true"를 추가하고, 사이드바 오픈 시 포커스 관리 (사이드바 내부로 이동, 닫을 시 이전 요소로 복귀)를 고려해야 합니다.
  • 개선 제안: 위 접근성 개선 사항들을 구현합니다.

1.4. 레이아웃 관련 파일

src/layouts/HomeLayout.tsx

  • 평가: 매우 간결하며, 특별한 개선점은 없습니다.
  • 개선 제안: 특이사항 없음.

src/layouts/ProtectedLayout.tsx

  • 성능: CreateLpModal이 항상 렌더링되고 있습니다.
  • 중복 코드 및 리팩토링 포인트:
    • FloatingButtonCreateLpModal 중복: ProtectedLayout.tsxHomePage.tsx 모두 FloatingButtonCreateLpModal을 렌더링하고 있습니다. ProtectedLayout의 목적이 인증된 사용자에게 공통 레이아웃을 제공하는 것이라면, 이 두 컴포넌트는 ProtectedLayout에만 존재해야 하며 HomePage에서는 제거되어야 합니다.
    • NavbaronToggleSidebar={() => {}}가 전달되는데, 이 레이아웃에서는 사이드바가 사용되지 않는 것으로 보입니다.
  • 개선 제안:
    • FloatingButtonCreateLpModal 중복 제거: HomePage.tsx에서 이 두 컴포넌트를 제거하여, ProtectedLayout에서만 렌더링되도록 합니다.
    • NavbarPropsonToggleSidebar를 선택적(?)으로 변경: Navbar 컴포넌트의 API를 더 유연하게 만듭니다.
    • 모달 컴포넌트 조건부 렌더링: CreateLpModalisOpen 상태가 true일 때만 조건부로 렌더링(마운트)하도록 변경합니다.

1.5. 페이지 관련 파일

src/pages/GoogleCallbackPage.tsx

  • 타입스크립트 문법 / 타입 개선점: error 변수에 any 타입이 사용되었습니다.
  • 잠재적 버그: localStorage.setItem("accessToken", JSON.stringify(accessToken)); 부분에서 accessToken이 이미 문자열이라면 JSON.stringify는 불필요하며, "토큰문자열" 형태로 저장되어 추후 파싱 시 문제가 발생할 수 있습니다. useLocalStorage 훅의 구현에 따라 중복 직렬화가 발생할 수 있습니다.
  • 중복 코드 및 리팩토링 포인트:
    • localStorage 직접 조작: localStorage.setItem을 직접 사용하는 것은 AuthContextlogin 또는 setTokens 함수를 통해 관리하는 것이 더 좋습니다.
    • alertsetTimeout을 사용한 UX: 로그인 성공 메시지를 alert로 띄우고 setTimeout으로 페이지를 이동시키는 방식은 사용자 경험 측면에서 부드럽지 않습니다.
  • 개선 제안:
    • AuthContext를 통한 토큰 관리: AuthContextsetTokens와 같은 함수를 추가하고, GoogleCallbackPage에서 이 함수를 호출하여 토큰을 저장하도록 합니다.
    • UX 개선: alert 대신 페이지 내에서 시각적인 성공 메시지를 보여주고 navigate 함수를 사용하여 자동으로 리디렉션하는 것이 더 부드러운 사용자 경험을 제공합니다.
    • JSON.stringify 제거: accessTokenrefreshToken이 이미 문자열이라면 JSON.stringify 없이 직접 저장하거나, useLocalStorage 훅 내에서만 직렬화를 처리하도록 일관성 있게 관리합니다.

src/pages/HomePage.tsx

  • 성능: Sidebar, CreateLpModal이 항상 렌더링되고 있습니다.
  • 중복 코드 및 리팩토링 포인트:
    • ProtectedLayout.tsx와 유사한 레이아웃 구조 및 Navbar, FloatingButton, CreateLpModal 컴포넌트 사용.
    • if (window.innerWidth < 768)와 같은 모바일 breakpoint 하드코딩.
    • closeSidebar 함수의 로직 if (window.innerWidth < 768) { setIsSidebarOpen(false); } else { setIsSidebarOpen(false); }에서 else 블록은 불필요합니다.
  • 개선 제안:
    • 공통 레이아웃 컴포넌트 추상화: ProtectedLayout.tsx와 함께 AppLayout과 같은 상위 레이아웃 컴포넌트를 생성하여 중복을 제거합니다.
    • FloatingButtonCreateLpModal 제거: 이 컴포넌트들은 ProtectedLayout에서 렌더링되므로 HomePage.tsx에서는 제거합니다.
    • useIsMobile 훅 적용: window.innerWidth 기반 로직을 추상화하는 커스텀 훅을 만들어서 사용합니다.
    • closeSidebar 로직 간결화: else 블록을 제거하고 setIsSidebarOpen(false)만 남깁니다.

src/pages/LoginPage.tsx

  • 타입스크립트 문법 / 타입 개선점: loginMutationonError 콜백에서 error: any 타입이 사용되었습니다.
  • 중복 코드 및 리팩토링 포인트: loginMutationonError에서 에러 메시지 처리가 반복됩니다. useForm에서 errors ?? {}errors가 항상 객체이므로 errors만 사용해도 무방합니다.
  • 개선 제안:
    • 에러 메시지 추출 유틸리티 함수 적용: getErrorMessage 함수를 적용합니다.
    • errors ?? {}errors로 간결화합니다.

src/pages/LpDetailPage.tsx

  • 성능: CreateLpModal, DeleteConfirm 모달이 isOpen 상태와 관계없이 항상 렌더링되고 있습니다. lp.likes.some(...)userInfo && userInfo.id === lp.authorId와 같은 조건부 로직이 JSX 내에서 여러 번 반복됩니다.
  • 타입스크립트 문법 / 타입 개선점: useContext(AuthContext)의 반환값을 명시적으로 타입 지정하지 않았습니다. useQueryuseMutationerrorany 타입이 사용되었습니다.
  • 중복 코드 및 리팩토링 포인트:
    • formatDate 함수가 다른 파일과 중복됩니다.
    • deleteLpMutation, toggleLikeMutationonError에서 에러 메시지 처리가 반복됩니다.
    • LP 상세 액션(deleteLpMutation, toggleLikeMutation) 및 관련 핸들러들이 많아지면 useLpActions(lpId)와 같은 커스텀 훅으로 분리하여 LpDetailPage의 로직을 더 간결하게 만들 수 있습니다.
    • 삭제 확인 모달(showDeleteConfirm)이 LpDetailPage 내부에 인라인으로 정의되어 있습니다.
  • 개선 제안:
    • 모달 컴포넌트 조건부 렌더링: CreateLpModal 및 삭제 확인 모달은 isOpen 또는 가시성 상태가 true일 때만 조건부로 렌더링합니다.
    • 계산된 값 변수에 저장: isLiked, isAuthor 등 반복적인 계산을 변수에 미리 저장하여 JSX에서 참조하도록 변경합니다.
    • 에러 메시지 추출 유틸리티 함수 적용: getErrorMessage 함수를 적용합니다.
    • formatDate 유틸리티 함수로 추출: src/utils/date.ts로 추출하여 재사용합니다.
    • LpDetailSkeleton 추가: LP 상세 페이지 로딩 시 스켈레톤 UI를 보여주는 컴포넌트를 구현하여 사용자 경험을 개선합니다.
    • select 옵션 활용: useQueryselect 옵션을 사용하여 데이터를 가져올 때 isLiked 값을 함께 파생시켜 반환할 수 있습니다.
    • DeleteConfirmModal 컴포넌트 분리: 삭제 확인 모달을 별도의 컴포넌트로 분리하여 관심사를 분리하고 재사용성을 높입니다.
    • 조건부 클래스 라이브러리 활용: clsx 또는 classnames와 같은 유틸리티 라이브러리를 사용하여 길고 복잡한 조건부 Tailwind 클래스를 더욱 명확하게 관리합니다.
    • 로그 조건부 처리: console.log('🚀 낙관적 업데이트:')와 같은 디버그 로그는 개발 환경에서만 활성화되도록 합니다.

src/pages/LpListPage.tsx

  • 중복 코드 / 리팩토링: useSidebar 커스텀 훅을 사용하여 사이드바 로직을 추상화한 것은 좋습니다. FloatingButton을 통해 handleCreateLp를 호출하지만, 현재는 console.log만 수행합니다.
  • 개선 제안: FloatingButton 클릭 시 실제 LP 생성 모달을 열거나 페이지로 이동하는 로직을 구현합니다.

src/pages/MyPage.tsx

  • 성능: useEffect 내부의 fetchMyInfoaccessToken이 변경될 때마다 실행되므로, accessToken 변경이 로그인/로그아웃 외에 발생하지 않는다면 큰 문제는 없습니다.
  • 타입스크립트 문법 / 타입 개선점: uploadImageMutationupdateUserMutationonError에서 error: any 타입이 사용되었습니다. setUploadedImageUrl(data.data.imageUrl);와 같이 datanull일 가능성을 고려해야 합니다.
  • 변수명, 함수명, 주석 품질: data라는 변수명보다는 myInfo와 같이 구체적인 데이터를 나타내는 이름이 더 좋습니다.
  • 중복 코드 및 리팩토링 포인트:
    • getMyInfouseEffect 내에서 useStatedata, isLoading, error를 수동으로 관리하고 있습니다. 이는 react-queryuseQuery 훅으로 대체될 수 있는 전형적인 패턴입니다.
    • 프로필 이미지(아바타)를 렌더링하는 로직(avatarUrl ? <img /> : <div />)이 메인 프로필 섹션과 수정 모달 내에서 중복됩니다.
    • 모달 닫기 버튼 (<svg>)의 Path 데이터가 긴 편입니다.
  • 개선 제안:
    • useQuery로 전환: getMyInfo 호출을 useQuery 훅으로 전환하여 react-query의 캐싱, 백그라운드 리페칭, 로딩/에러 상태 관리 등의 이점을 활용하고 코드의 복잡성을 줄입니다.
    • 에러 메시지 추출 유틸리티 함수 적용: getErrorMessage 함수를 적용합니다.
    • ProfileAvatar 컴포넌트 추출: 프로필 아바타 표시 로직을 별도의 ProfileAvatar 컴포넌트로 분리하여 재사용성을 높입니다.
    • 공통 아이콘 컴포넌트 활용: lucide-reactreact-icons와 같은 라이브러리의 아이콘을 사용하는 것을 고려합니다.
    • alert 메시지 개선: Toast 알림 라이브러리를 도입하여 사용자 피드백을 개선합니다.

src/pages/NotFoundPage.tsx

  • 평가: 단순한 404 페이지입니다.
  • 개선 제안: 특이사항 없음.

src/pages/SignupPage.tsx, src/pages/SignupPageEmail.tsx, src/pages/SignupPageName.tsx, src/pages/SignupPagePassword.tsx

  • 평가: react-hook-formzod를 사용하여 다단계 회원가입 폼을 잘 구현했습니다. 각 단계별 폼 필드와 유효성 검사 로직이 잘 구현되어 있으며, useFormContext를 사용하여 폼 상태를 공유하는 방식이 좋습니다. 비밀번호 표시/숨김 토글 버튼에 aria-label을 추가하여 접근성을 고려한 점은 훌륭합니다.
  • 중복 코드 / 리팩토링:
    • SignupPage에서 Navbar 컴포넌트에 onToggleSidebar={() => {}}를 전달하는 부분이 있는데, 사이드바가 없는 페이지입니다.
    • handleBack 함수 내 if-else if-else 구조가 반복적입니다.
    • 세 컴포넌트 모두 isDisabled 로직 (!value.trim() || Boolean(errors.field))이 유사합니다.
    • SignupPagePassword.tsx의 비밀번호 표시/숨김 토글 로직은 여러 곳에서 사용될 수 있는 패턴입니다.
  • 개선 제안:
    • Navbar onToggleSidebar prop 제거: SignupPage에서 Navbar를 사용할 때 onToggleSidebar prop을 제거합니다.
    • handleBack 로직 개선: switch 문이나 Map을 이용하여 handleBack 함수를 더 간결하게 표현합니다.
    • PasswordInput 컴포넌트 추출: 비밀번호 입력 필드와 시각화 토글 버튼 로직을 재사용 가능한 PasswordInput 컴포넌트로 추출하여 코드 중복을 줄입니다.
    • 아바타 플레이스홀더 접근성 강화 (SignupPageName.tsx): 👤 이모지가 사용된 아바타 플레이스홀더 divaria-label="프로필 아바타 플레이스홀더"와 같은 속성을 추가합니다.
    • noValidate 속성 제거: react-hook-form이 클라이언트 측 유효성 검사를 처리하므로, form 태그의 noValidate 속성은 불필요합니다.

1.6. 프로바이더 및 유틸리티 파일

src/provider/AuthProvider.tsx

  • 성능: synchronizeTokensFromStorage 함수 및 fetchUserInfo 호출은 의존성 배열이 안정적이므로 큰 성능 문제는 없습니다.
  • 타입스크립트 문법 / 타입 개선점: handleUserLoginlogout 함수 내 error: any 타입은 구체적인 타입으로 변경하는 것이 좋습니다.
  • 잠재적 버그: localStorage.setItem 관련 내용은 GoogleCallbackPage.tsx와 동일한 문제입니다. useLocalStorage 훅의 구현에 따라 중복 직렬화가 발생할 수 있습니다.
  • 중복 코드 / 리팩토링: alert() 메시지 사용은 MyPage.tsx와 동일하게 개선이 필요합니다.
  • 개선 제안:
    • AxiosError 타입 적용: try-catch 블록의 error 매개변수 타입을 AxiosError<ErrorResponse>로 구체화하여 에러 처리 로직을 강화합니다.
    • 로그아웃 후 리다이렉션 개선: 로그아웃 성공 시 alert() 후 메인 페이지로 이동하는 것보다, 알림과 함께 navigate('/login') 또는 navigate('/')를 사용하여 사용자 흐름을 더 자연스럽게 만듭니다.
    • JSON.stringify 제거: accessTokenrefreshToken이 이미 문자열이라면 JSON.stringify 없이 직접 저장하거나, useLocalStorage 훅 내에서만 직렬화를 처리하도록 일관성 있게 관리합니다.

src/utils/validate.ts

  • 타입스크립트: UserSigninInformationRecord<keyof UserSigninInformation, string> 타입 정의가 정확합니다.
  • 중복 코드 / 리팩토링: validateSignin 함수가 단순히 validateUser 함수를 호출하는 형태로 되어 있어 약간의 중복처럼 보일 수 있습니다. SignupPage에서 zod를 사용하는 것을 고려할 때, 이 파일의 수동 유효성 검사 로직도 zod 스키마로 통합하여 일관성을 유지하는 것이 좋습니다.
  • 개선 제안:
    • Zod를 이용한 유효성 검사 통합: SignupPage에서 사용하는 zodsrc/utils/validate.ts의 로그인 유효성 검사에도 적용하여, 애플리케이션 전반의 유효성 검사 로직을 zod로 통일합니다.
    • validateSignin의 존재 이유를 명확히 하거나, validateUservalidateSignin으로 다시 export 하는 것을 고려할 수 있습니다.

src/types/api.ts, src/types/auth.ts, src/types/common.ts

  • 평가: API 응답 및 요청에 대한 타입 정의가 매우 상세하고 잘 구조화되어 있습니다. 타입 안정성에 크게 기여할 것입니다. ApiResponse와 같은 공통 응답 타입을 정의한 점도 훌륭합니다.
  • 개선 제안: 특이사항 없음.

src/vite-env.d.ts, tsconfig.app.json, tsconfig.json, tsconfig.node.json, vite.config.ts

  • 평가: Vite 및 TypeScript 환경 설정이 표준적으로 잘 되어 있습니다.
  • 개선 제안: 특이사항 없음.

1.7. 기타 프로젝트 설정

package.jsonpackage-lock.json (Part 5 통합)

  • 문제점:
    • package.jsonreact-routerreact-router-dom 외에 Router: "^2.1.0"이라는 의존성이 존재합니다. 이는 표준 React Router와 관련된 패키지가 아니며, 불필요한 의존성은 번들 크기를 증가시키고 잠재적인 충돌을 야기할 수 있습니다.
    • 광범위한 의존성 업데이트가 이루어졌지만, 주요 의존성의 메이저 버전 변경(예: eslint 9.x, @typescript-eslint 8.x)에 대한 Breaking Changes 검토 및 영향 요약이 부족합니다.
    • Node.js 엔진 요구사항 변화(Node.js 18 이상 요구)가 반영되지 않았을 수 있습니다.
  • 개선 제안:
    • 불필요한 Router 의존성 제거: Router 패키지의 의도된 사용처가 없다면 package.json에서 제거하고 npm install 또는 yarn install을 다시 실행하여 package-lock.json을 업데이트합니다.
    • Node.js 버전 호환성 검토 및 업데이트: .nvmrc 파일, package.jsonengines 필드, CI/CD 파이프라인에서 사용되는 Node.js 버전이 새로운 요구사항을 충족하는지 확인하고 필요시 업데이트합니다.
    • 주요 의존성 메이저 버전 변경 사항 검토 및 문서화: eslint@typescript-eslint와 같은 주요 업데이트로 인해 발생할 수 있는 잠재적인 영향(새로운 린팅 에러, 구문 변경 등)에 대한 요약과 코드 마이그레이션 가이드라인을 PR 설명에 포함하는 것이 좋습니다.
    • 번들 크기 및 빌드 성능 지표 확인: 번들 분석 도구를 사용하여 업데이트 전후의 번들 크기를 비교하고, CI에서 빌드 시간을 모니터링하여 성능 회귀가 없는지 확인합니다.
    • 린팅 및 포맷팅 규칙 재확인 및 보안 취약점 감사 실행: eslint --fix를 실행하고 Prettier와의 충돌을 확인하며, npm audit 또는 yarn audit을 실행하여 보안 취약점을 점검합니다.
    • peerDependencies 충족 여부 확인: 프로젝트의 주요 의존성 버전이 peerDependencies 요구사항을 모두 충족하는지 검토합니다.

2. 최종 구체적 개선 제안 (통합 및 요약)

위에서 제시된 상세 피드백을 바탕으로, 코드의 안정성, 성능, 유지보수성, 사용자 경험 및 접근성을 더욱 향상시키기 위한 핵심적인 통합 개선 제안 8가지를 드립니다.

  1. [코드 품질 / 재사용성] 공통 UI 컴포넌트 및 유틸리티 추출:

    • SVG 아이콘 컴포넌트 분리: Navbar.tsx, Sidebar.tsx, CommentList.tsx, CreateLpModal.tsx, LpCard.tsx 등 여러 파일에 인라인으로 존재하는 SVG 아이콘들을 /src/components/icons 디렉터리 내에 독립적인 컴포넌트로 추출하여 중복을 제거하고 재사용성을 높입니다.
    • 인증 상태 표시/로그아웃 버튼 컴포넌트 분리: Navbar.tsxSidebar.tsx에 중복된 인증 상태 표시(AuthStatusDisplay.tsx) 및 로그아웃 버튼(LogoutButton.tsx) 로직을 별도 컴포넌트로 분리합니다.
    • CommentItemErrorRetryMessage 컴포넌트 분리: CommentList.tsx의 복잡한 댓글 렌더링 로직을 CommentItem.tsx로 분리하고, CommentList.tsxLpList.tsx의 반복되는 에러 및 재시도 UI를 ErrorRetryMessage.tsx와 같은 공통 컴포넌트로 분리하여 가독성 및 유지보수성을 향상시킵니다.
    • formatDate 유틸리티 함수 추출: CommentList.tsx, LpCard.tsx, LpDetailPage.tsx 등에서 중복 정의된 formatDate 함수를 src/utils/date.ts 파일로 추출하고, Intl.DateTimeFormatOptions를 유연하게 받을 수 있도록 하여 재사용성을 높입니다.
  2. [성능 / 리팩토링] 모달 컴포넌트 조건부 렌더링 및 레이아웃 중복 제거:

    • ProtectedLayout.tsx, HomePage.tsx, LpDetailPage.tsx 등에서 CreateLpModal 및 삭제 확인 모달과 같은 모달 컴포넌트는 isOpen 또는 해당 모달의 가시성 상태가 true일 때만 조건부로 렌더링(마운트)하도록 변경하여 불필요한 리소스 소모를 줄이고 렌더링 성능을 개선합니다.
    • FloatingButtonCreateLpModalProtectedLayout.tsxHomePage.tsx 모두에 존재하여 중복됩니다. 이 컴포넌트들은 인증된 사용자에게 공통적으로 제공되어야 하므로, ProtectedLayout.tsx에만 남기고 HomePage.tsx에서는 제거합니다.
  3. [타입 안전성] any 타입 최소화 및 일관된 에러 처리 도입:

    • GoogleCallbackPage.tsx, LoginPage.tsx, MyPage.tsx, AuthProvider.tsx, useMutation 훅의 onError 콜백 등 여러 파일에서 error: any로 처리되는 에러 타입을 import { AxiosError } from 'axios';를 활용하여 AxiosError<YourErrorResponseType>와 같이 구체적으로 명시하여 에러 핸들링의 견고성을 높입니다.
    • 반복되는 에러 메시지 추출 및 alert 로직을 src/utils/error.ts 파일의 getErrorMessage 함수로 추상화하여 중복을 제거하고 일관성을 확보합니다.
  4. [인증 / 보안] 일관된 토큰 관리 및 보안 강화:

    • GoogleCallbackPage.tsx에서 localStorage.setItem을 직접 사용하는 대신, AuthContext에 토큰을 설정하는 전용 함수(예: setTokens 또는 login 함수 확장)를 추가하여 모든 인증 관련 토큰 관리가 AuthContext를 통해 이루어지도록 합니다.
    • refreshToken은 HTTP-only 쿠키에 저장하고, accessTokensessionStorage 또는 메모리에 유지하는 것을 고려하여 XSS 공격으로부터 토큰을 보호합니다.
    • GoogleCallbackPage.tsx에서 localStorage.setItemJSON.stringify 호출을 제거하여 불필요한 중복 직렬화를 방지하고 파싱 문제를 해결합니다.
  5. [접근성 / UX] 모달 및 폼 요소 접근성 강화 및 사용자 피드백 개선:

    • 모든 모달 컴포넌트(LoginRequiredModal.tsx, CreateLpModal.tsx, Sidebar.tsx 내 회원 탈퇴 모달 등)에 role="dialog", aria-modal="true", aria-labelledby, aria-describedby 속성을 추가하고, 모달이 열릴 때 초점을 모달 내부로 가두고 닫힐 때 이전 요소로 복원하는 로직을 구현합니다.
    • FormInput.tsx 컴포넌트 내 오류 메시지를 표시하는 <p> 태그에 aria-live="assertive" 속성을 추가하여 스크린 리더 사용자가 오류를 즉시 인지하도록 합니다.
    • alert() 호출을 대체할 react-hot-toastsonner와 같은 라이브러리를 사용하여 사용자에게 비침범적이고 일관된 피드백 경험을 제공합니다. 로그인 실패 또는 토큰 만료 시 사용자에게 더 친화적인 메시지를 표시합니다.
  6. [리팩토링 / 유지보수성] react-query 기반 데이터 관리 전환 및 코드 추상화:

    • MyPage.tsx에서 사용자 정보를 가져오는 useState/useEffect 기반의 수동 로직을 react-queryuseQuery 훅으로 전환하여 데이터 페칭, 캐싱, 로딩 및 에러 상태 관리를 자동화하고 코드 복잡성을 줄입니다.
    • LpDetailPage.tsx의 LP 상세 액션(deleteLpMutation, toggleLikeMutation) 및 관련 핸들러들을 useLpActions(lpId)와 같은 커스텀 훅으로 분리하여 LpDetailPage의 로직을 더 간결하게 만듭니다.
    • src/utils/validate.ts의 로그인 유효성 검사 로직을 SignupPage에서 사용 중인 zod 스키마로 통합하여, 애플리케이션 전반의 유효성 검사 방식에 일관성을 부여합니다.
  7. [코드 품질 / 이름 규칙] 명확한 이름 규칙 및 중복 제거:

    • src/hooks/useLocalStorage.ts 파일은 실제 React Hook의 규칙을 따르지 않으므로 use 접두사를 제거하고 createLocalStorageManager 등으로 이름을 변경합니다. 또한 getItem 함수에 제네릭 타입을 추가하여 반환 값의 타입 안정성을 높입니다.
    • src/constants/key.ts 파일에서 LOCAL_STORAGE_KEY (단수형)는 @deprecated JSDoc 태그를 추가하고, 모든 코드에서 LOCAL_STORAGE_KEYS (복수형)를 사용하도록 마이그레이션이 완료되면 해당 상수를 제거합니다.
    • HomePage.tsxcloseSidebar 함수의 불필요한 else 블록을 제거하여 코드를 간결하게 만듭니다.
  8. [반응형 / UX] 반응형 로직 추상화 및 상세 UX 개선:

    • window.innerWidth < 768와 같은 모바일 화면 감지 로직이 Sidebar.tsx, HomePage.tsx 등 여러 곳에서 반복됩니다. 이를 src/hooks/useIsMobile.ts와 같은 커스텀 훅으로 만들어 재사용성을 높이고 코드 가독성을 개선합니다.
    • CreateLpModal.tsx에서 태그 추가 후 입력 필드에 자동으로 포커스를 재설정하여 연속적인 태그 입력을 편리하게 만들고, 플레이스홀더 이미지 URL과 같은 매직 스트링은 상수로 정의하여 관리합니다.
    • LpCard.tsx에서 LP 상세 페이지로 이동하는 클릭 가능한 divreact-router-dom<Link> 컴포넌트로 변경하여 웹 표준 및 접근성을 준수합니다.

전반적으로 API 연동과 인증 흐름을 구현하려는 좋은 시도이며, 많은 부분에서 견고함이 보입니다. 위에 제시된 개선 제안들을 통해 코드의 안정성, 성능, 유지보수성, 사용자 경험 및 접근성을 더욱 향상시킬 수 있을 것입니다.

수고 많으셨습니다!

Copy link
Copy Markdown
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.

8주차도 고생하셨습니다! 최근에 업데이트 된 React-Compiler 라는 자동 최적화 도구가 나왔으니 같이 공부해보면 좋을 것 같아요!

@huheyun huheyun merged commit aec7f6f into main Dec 16, 2025
1 check passed
@huheyun huheyun deleted the gureum/week08 branch December 16, 2025 11:21
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