Skip to content

[refactor] Header 컴포넌트 리팩터링 - View와 service 로직 분리 및 선언 순서 개선#340

Merged
seongwon030 merged 8 commits intodevelop-fefrom
refactor/#339-header-view-logic-separation-FE-92
Apr 28, 2025
Merged

[refactor] Header 컴포넌트 리팩터링 - View와 service 로직 분리 및 선언 순서 개선#340
seongwon030 merged 8 commits intodevelop-fefrom
refactor/#339-header-view-logic-separation-FE-92

Conversation

@seongwon030
Copy link
Member

@seongwon030 seongwon030 commented Apr 27, 2025

#️⃣연관된 이슈

ex) #339

📝작업 내용

Header 컴포넌트 통합

  • 데스크탑 헤더 위치 : src/components/common/Header.tsx
  • 모바일 헤더 위치 : src/pages/MainPage/MobileHeader/MobileHeader.tsx

해당 구조의 단점

  • 공통 로직이 존재합니다. 이로 인해 변경 사항이 생길 시 두 개의 파일을 변경해야 하는 번거로움이 있습니다.
  • 두 파일이 속한 폴더가 서로 멀리 위치해 있습니다.
  • view와 service 로직이 같은 파일에 있습니다.

모바일 헤더를 Header로 가져오기

  1. 모바일 훅으로 분기 나누기 75fe66a
  2. 공통 로직 분리 및 service로직 분리하기 07a4ec7
  3. view 로직 분리하기 a4e0812
  4. 스타일 파일 병합 985df64

중점적으로 리뷰받고 싶은 부분(선택)

처음으로 서비스 로직을 분리해봤습니다. 구조에 대해서 피드백 부탁드립니다!

논의하고 싶은 부분(선택)

  • handleClick같은 함수명을 어떤 식으로 바꾸면 좋을까요?

🫡 참고사항

Summary by CodeRabbit

Summary by CodeRabbit

  • 신규 기능
    • 모바일 환경에서 최적화된 헤더 UI가 추가되었습니다.
    • 모바일/데스크톱 환경에 따라 각각 다른 헤더가 표시됩니다.
  • 리팩터
    • 헤더 컴포넌트가 모바일과 데스크톱 전용 컴포넌트로 분리되었습니다.
    • 헤더 관련 네비게이션 및 추적 로직이 별도의 커스텀 훅으로 분리되었습니다.
  • 기타
    • 기존 메인 페이지의 모바일 헤더가 제거되었습니다.

@seongwon030 seongwon030 added 🔨 Refactor 코드 리팩토링 💻 FE Frontend labels Apr 27, 2025
@seongwon030 seongwon030 requested a review from oesnuj April 27, 2025 11:52
@seongwon030 seongwon030 self-assigned this Apr 27, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 27, 2025

"""

Walkthrough

이 변경사항은 Header 컴포넌트의 리팩터링을 중심으로, 모바일과 데스크톱 뷰를 각각 별도의 컴포넌트로 분리하고, 네비게이션 및 트래킹 로직을 커스텀 훅(useHeaderService)으로 분리하였습니다. 모바일 환경 감지를 위한 useIsMobile 훅이 추가되었으며, 관련 스타일 컴포넌트와 기존 모바일 헤더 컴포넌트가 통합 및 제거되었습니다. 전체적으로 헤더의 뷰와 서비스 로직이 명확히 분리되어 구조가 개선되었습니다.

Changes

파일/경로 그룹 변경 요약
frontend/src/components/common/Header/Header.tsx Header 컴포넌트를 모바일/데스크톱 뷰로 분리, 서비스 로직 훅 적용, 뷰 분기 렌더링 적용
frontend/src/components/common/Header/Header.styles.ts 모바일 헤더용 스타일 컴포넌트 추가
frontend/src/hooks/useIsMobile.ts 모바일 환경 감지 커스텀 훅 추가
frontend/src/services/header/useHeaderService.ts 헤더 네비게이션 및 트래킹 로직 분리 커스텀 훅 추가
frontend/src/pages/MainPage/components/MobileHeader/MobileHeader.tsx,
frontend/src/pages/MainPage/components/MobileHeader/MobileHeader.styles.ts
기존 모바일 헤더 컴포넌트 및 스타일 파일 삭제
frontend/src/pages/MainPage/MainPage.tsx MainMobileHeader import 및 사용 부분 삭제

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Header
    participant useIsMobile
    participant useHeaderService
    participant DesktopHeader
    participant MobileHeader

    User->>Header: 페이지 진입
    Header->>useIsMobile: 현재 뷰포트 확인
    useIsMobile-->>Header: isMobile 여부 반환
    Header->>useHeaderService: 네비/트래킹 핸들러 준비
    alt isMobile
        Header->>MobileHeader: 모바일 헤더 렌더링 (핸들러 전달)
    else
        Header->>DesktopHeader: 데스크톱 헤더 렌더링 (핸들러 전달)
    end
Loading

Assessment against linked issues

Objective Addressed Explanation
Header 컴포넌트 리팩터링 - View로직 분리 및 선언 순서 개선 (FE-92)

Possibly related issues

Suggested labels

✨ Feature, 🎨 Design
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 266e070 and b3ca636.

📒 Files selected for processing (2)
  • frontend/src/components/common/Header/Header.tsx (1 hunks)
  • frontend/src/services/header/useHeaderService.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/services/header/useHeaderService.ts
  • frontend/src/components/common/Header/Header.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@netlify
Copy link

netlify bot commented Apr 27, 2025

Deploy Preview for moadong ready!

Name Link
🔨 Latest commit b3ca636
🔍 Latest deploy log https://app.netlify.com/sites/moadong/deploys/680f14e46eb1980008fb810b
😎 Deploy Preview https://deploy-preview-340--moadong.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 42
Accessibility: 87
Best Practices: 92
SEO: 92
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (10)
frontend/src/hooks/useIsMobile.ts (3)

4-4: 매직 넘버 상수화 고려해보세요.

모바일 기준점으로 사용하는 500px 값은 매직 넘버입니다. 나중에 이 값을 변경해야 할 경우 여러 파일에서 수정해야 할 수 있습니다. 스타일 상수 파일에 정의하여 재사용하는 것이 좋습니다.

-  const [isMobile, setIsMobile] = useState(window.innerWidth <= 500);
+  const MOBILE_BREAKPOINT = 500; // 또는 상수 파일에서 import
+  const [isMobile, setIsMobile] = useState(window.innerWidth <= MOBILE_BREAKPOINT);

7-8: 리사이즈 핸들러도 상수를 사용하세요.

이벤트 핸들러에서도 동일한 매직 넘버를 사용하고 있습니다. 상수화된 값을 여기서도 사용해야 합니다.

+  const MOBILE_BREAKPOINT = 500; // 또는 상수 파일에서 import
   const handleResize = () => {
-    setIsMobile(window.innerWidth <= 500);
+    setIsMobile(window.innerWidth <= MOBILE_BREAKPOINT);
   };

3-16: SSR 대응 필요

이 훅은 window 객체에 직접 접근하므로 서버 사이드 렌더링 환경에서는 오류가 발생할 수 있습니다. SSR 환경을 고려하여 초기 상태 설정과 이벤트 리스너 등록을 수정할 필요가 있습니다.

 const useIsMobile = () => {
-  const [isMobile, setIsMobile] = useState(window.innerWidth <= 500);
+  const [isMobile, setIsMobile] = useState(false);
 
   useEffect(() => {
+    // SSR 환경에서 안전하게 초기값 설정
+    setIsMobile(window?.innerWidth <= 500);
+    
     const handleResize = () => {
       setIsMobile(window.innerWidth <= 500);
     };
 
     window.addEventListener('resize', handleResize);
     return () => window.removeEventListener('resize', handleResize);
   }, []);
 
   return isMobile;
 };
frontend/src/services/header/useHeaderService.ts (3)

5-8: 상수명 개선

trackEventNames는 용도를 더 명확히 드러내는 이름이 좋습니다. 헤더의 홈 버튼 클릭에 관한 이벤트 이름이므로 homeButtonTrackEventNames와 같이 더 구체적인 이름을 사용하는 것이 좋습니다.

-const trackEventNames = {
+const homeButtonTrackEventNames = {
   desktop: 'Home Button Clicked',
   mobile: 'Mobile Home Button Clicked',
 } as const;

15-20: 함수 매개변수 타입 개선

navigateToHome 함수에서 device 매개변수의 타입을 trackEventNames에서 유도하고 있는데, 이는 상수명이 변경될 경우 타입도 함께 변경해야 합니다. 타입을 직접 정의하거나 유니온 타입을 사용하는 것이 더 명확할 수 있습니다.

-  const navigateToHome = (device: keyof typeof trackEventNames) => {
+  const navigateToHome = (device: 'desktop' | 'mobile') => {
     navigate('/');
     setKeyword('');
     setInputValue('');
-    trackEvent(trackEventNames[device]);
+    trackEvent(homeButtonTrackEventNames[device]);
   };

22-26: 새 탭에서 열기 고려

소개 페이지를 현재 탭에서 여는 것은 사용자가 현재 작업 중인 내용을 잃게 할 수 있습니다. 외부 링크는 일반적으로 새 탭에서 여는 것이 더 나은 사용자 경험을 제공합니다.

 const goIntroducePage = () => {
-  window.location.href =
-    'https://valiant-schooner-12c.notion.site/1a64ac84bab3805287e0cef50b563370';
+  window.open(
+    'https://valiant-schooner-12c.notion.site/1a64ac84bab3805287e0cef50b563370',
+    '_blank',
+    'noopener,noreferrer'
+  );
   trackEvent('Introduce Button Clicked');
 };
frontend/src/components/common/Header/Header.tsx (2)

36-38: 접근성 속성 중복

MobileMenu 버튼에 aria-labelalt 속성이 모두 동일한 값으로 설정되어 있습니다. 이미지에는 alt 속성만, 버튼에는 aria-label 속성만 있으면 충분합니다.

-    <Styled.MobileMenu aria-label='메뉴 버튼'>
+    <Styled.MobileMenu>
       <img src={MenuBar} alt='메뉴 버튼' onClick={handleMenuClick} />
     </Styled.MobileMenu>

또는 alt 속성을 더 구체적으로 수정:

     <Styled.MobileMenu aria-label='메뉴 버튼'>
-      <img src={MenuBar} alt='메뉴 버튼' onClick={handleMenuClick} />
+      <img src={MenuBar} alt='' onClick={handleMenuClick} />
     </Styled.MobileMenu>

31-33: 이미지 클릭 핸들러 위치 변경 고려

이미지에 클릭 핸들러를 직접 부여하는 대신, 상위 버튼 컴포넌트에 핸들러를 부여하는 것이 더 접근성 측면에서 좋습니다. 이렇게 하면 키보드 탐색도 자연스럽게 지원됩니다.

데스크톱 헤더:

-        <Styled.LogoButtonStyles>
+        <Styled.LogoButtonStyles onClick={() => handleHomeClick('desktop')}>
           <img
             src={DesktopMainIcon}
             alt='홈 버튼'
-            onClick={() => handleHomeClick('desktop')}
           />
         </Styled.LogoButtonStyles>

모바일 헤더도 비슷하게 수정할 수 있습니다.

Also applies to: 55-56

frontend/src/components/common/Header/Header.styles.ts (2)

109-121: 중복된 버튼 스타일링

MobileMainIconMobileMenu 컴포넌트는 스타일링이 매우 유사합니다. 재사용 가능한 base 버튼 스타일을 만들고 확장하는 방식으로 리팩토링하면 코드 중복을 줄일 수 있습니다.

+export const MobileIconButton = styled.button`
+  background-color: transparent;
+  border: none;
+  cursor: pointer;
+
+  img {
+    width: 100%;
+    height: auto;
+    object-fit: cover;
+  }
+`;
+
-export const MobileMainIcon = styled.button`
+export const MobileMainIcon = styled(MobileIconButton)`
   width: 26px;
   height: 22px;
-  background-color: transparent;
-  border: none;
-  cursor: pointer;
-
-  img {
-    width: 26px;
-    height: auto;
-    object-fit: cover;
-  }
 `;

... (비슷한 방식으로 다른 버튼 컴포넌트도 수정)

Also applies to: 145-157


84-84: 매직 넘버 상수화 고려

미디어 쿼리에서 사용하는 500px 값은 useIsMobile.ts에서도 사용되는 매직 넘버입니다. 모바일 구분 기준이 변경되면 모든 파일에서 수정해야 하므로, 이 값을 상수로 추출하여 공유하는 것이 좋습니다.

+// 별도의 상수 파일에 정의하고 import하는 것이 이상적입니다
+const MOBILE_BREAKPOINT = '500px';

 export const MobileHeaderContainer = styled.header`
   display: none;
 
-  @media (max-width: 500px) {
+  @media (max-width: ${MOBILE_BREAKPOINT}) {
     position: fixed;
     display: flex;
     /* ... */
   }
 `;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e48192 and ed0ec85.

📒 Files selected for processing (7)
  • frontend/src/components/common/Header/Header.styles.ts (1 hunks)
  • frontend/src/components/common/Header/Header.tsx (1 hunks)
  • frontend/src/hooks/useIsMobile.ts (1 hunks)
  • frontend/src/pages/MainPage/MainPage.tsx (0 hunks)
  • frontend/src/pages/MainPage/components/MobileHeader/MobileHeader.styles.ts (0 hunks)
  • frontend/src/pages/MainPage/components/MobileHeader/MobileHeader.tsx (0 hunks)
  • frontend/src/services/header/useHeaderService.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • frontend/src/pages/MainPage/MainPage.tsx
  • frontend/src/pages/MainPage/components/MobileHeader/MobileHeader.tsx
  • frontend/src/pages/MainPage/components/MobileHeader/MobileHeader.styles.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
frontend/src/services/header/useHeaderService.ts (1)
frontend/src/context/SearchContext.tsx (1)
  • useSearch (33-39)
🔇 Additional comments (8)
frontend/src/hooks/useIsMobile.ts (1)

1-16: 좋은 커스텀 훅 구현입니다!

이 훅은 모바일 디바이스 감지에 필요한 로직을 잘 캡슐화했습니다. 창 크기 변경에 대한 이벤트 리스너 등록과 정리가 적절히 처리되었습니다.

frontend/src/services/header/useHeaderService.ts (1)

1-37: 서비스 로직 분리가 잘 되었습니다!

헤더의 서비스 로직을 별도의 훅으로 분리한 것은 매우 좋은 구조입니다. 이벤트 트래킹 및 네비게이션 로직이 깔끔하게 정리되었습니다.

frontend/src/components/common/Header/Header.tsx (5)

1-10: 헤더 컴포넌트 리팩토링 잘 되었습니다!

모바일과 데스크톱 헤더를 통합하고 관련 로직을 분리한 구조가 매우 깔끔합니다. 각 기능별로 책임이 명확히 분리되어 있어 유지보수하기 좋은 코드가 되었습니다.


11-20: 인터페이스 명확히 정의되었습니다.

모바일 헤더와 데스크톱 헤더의 props 인터페이스가 잘 정의되어 있어 타입 안전성이 보장됩니다.


22-41: 모바일 헤더 컴포넌트가 깔끔합니다.

함수형 컴포넌트와 화살표 함수를 사용해 간결하게 정의되었습니다. 이미지에 대한 접근성 속성(alt)도 적절히 추가되어 있습니다.


43-67: 데스크톱 헤더 컴포넌트가 깔끔합니다.

함수형 컴포넌트와 화살표 함수를 사용해 간결하게 정의되었습니다. 관리자 페이지에 따른 조건부 렌더링도 잘 구현되어 있습니다.


69-88: 메인 헤더 컴포넌트가 깔끔합니다.

useIsMobile 훅을 사용한 조건부 렌더링과 필요한 로직만 전달하는 방식이 좋습니다. 코드가 간결하고 이해하기 쉽습니다.

frontend/src/components/common/Header/Header.styles.ts (1)

81-157: 모바일 스타일 컴포넌트가 잘 구현되었습니다.

모바일 헤더를 위한 스타일 컴포넌트들이 디자인 요구사항에 맞게 잘 구현되었습니다. 특히 500px 기준점을 useIsMobile 훅과 일관되게 사용한 점이 좋습니다.

Copy link
Member

@oesnuj oesnuj left a comment

Choose a reason for hiding this comment

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

Header 코드가 복잡했는데 훨씬 간결하고 가독성도 좋네요!
분리 좋습니다

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

Labels

💻 FE Frontend 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor] FE-92 Header 컴포넌트 리팩터링 - View와 service 로직 분리 및 선언 순서 개선

2 participants