Skip to content

Comments

[refactor] LazyImage 컴포넌트 기능 개선 및 성능 최적화#913

Merged
lepitaaar merged 5 commits intodevelop-fefrom
refactor/#907-improve-lazy-image-MOA-401
Dec 7, 2025
Merged

[refactor] LazyImage 컴포넌트 기능 개선 및 성능 최적화#913
lepitaaar merged 5 commits intodevelop-fefrom
refactor/#907-improve-lazy-image-MOA-401

Conversation

@seongwon030
Copy link
Member

@seongwon030 seongwon030 commented Dec 6, 2025

#️⃣연관된 이슈

ex) #907

📝작업 내용

문제점

1. 불필요한 timeout 설정

timeout 100ms가 설정되어 있어 사용자 경험을 해칠 수 있습니다.

let timeout: ReturnType<typeof setTimeout>;

    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        const delay = 100;
        timeout = setTimeout(() => {
          setIsVisible(true);
        }, delay);
        observer.disconnect();
      }

React와 Oberver 순서에서도 딜레이는 불필요합니다.

Intersection Observer가 감지함 -> React State 변경 -> Image 태그 렌더링 -> 브라우저가 이미지 요청.

딜레이를 설정하면 이 흐름을 강제로 끊게 됩니다.

2. 모든 이미지에 지연로딩 적용

Intersection Obersever로 활동사진 슬라이드의 "다음 사진"의 교차점을 감지하여 지연로딩을 시키는 것이 목적이었습니다.

하지만 기존 로직으로는 최초 로딩 시 보이는 이미지들도 지연 로딩하고 있었습니다.

개선

1. setTimeout 제거

setTimeout 관련 코드를 제거하고 observer만 남겼습니다. 이제 100ms 딜레이없이 바로 이미지를 로드해 옵니다.

    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsVisible(true);
          observer.disconnect();
        }
      },
      {
        threshold,
      }

2. isEager prop추가

최초 렌더링 시 보이는 이미지는 즉시 로딩하도록 isEager를 LazyImageProps에 추가했습니다

그리고 isEager의 기준을 index < 4로 설정하여 데스크탑, 태블릿, 모바일 모두 최초 렌더링 이미지 개수를 4개로 통일했습니다.

최초 로드 시 보이는 이미지 최대 개수가 데스크탑 3개, 태블릿 2개, 모바일 4개였기에 4개를 기준으로 잡았습니다.

이미지 개수 설정 고민

  1. useDevice로 반응형마다 렌더링 이미지 개수 설정

반응형 훅인 useDevice를 사용할 시 자바스크립트가 로드되고 실행되어야만 화면 크기를 알 수 있기에 비효율적.

  1. css 미디어 쿼리 이용

css만으로 nth-child를 통해 Eager 로딩 개수를 정하는 방법도 고민했는데, 반응형 훅을 사용하는 것보다 확실히 LCP 손해가 없고 책임 분리에도 용이할 것 같았습니다.

그러나.. LCP까지 고려할 정도로 사이트가 사용성이 나쁘지도 않고, 또 index < 4라는 하나의 코드로도 모든 반응형을 커버할 수 있는데 이 방법을 적용하는 것은 오버 엔지니어링이라 판단했습니다.

3. 파일 위치 변경

활동사진을 위한 공통 훅이기에 파일 위치를 옮겼습니다.

기존: src/common/Lazy~
변경: src/pages/ClubDetailPage/components/PhotoList/Lazy~

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

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

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

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

  • 새로운 기능
    • ClubDetailPage 전용 지연 로딩 이미지 컴포넌트 추가(플레이스홀더, 지연/즉시 로드, 로드 상태 전환).
  • 개선사항
    • 처음 4개 이미지는 즉시 로드되도록 조정하여 초기 렌더 성능 향상.
    • 이미지 로드 시 배경/투명도 전환으로 부드러운 시각 효과 제공.
    • 창 크기 기준을 상수로 분리하고 리사이즈 이벤트 정리 추가.
  • 테스트
    • LazyImage 관련 테스트 리팩토링 및 타이밍 의존성 제거.

✏️ Tip: You can customize this high-level summary in your review settings.

- LazyImage에 커스터마이징 가능한 props 추가 (placeholder, threshold, rootMargin, isEager)
- 이미지 로딩 완료 시 fade-in 효과 추가로 UX 개선
- IntersectionObserver 설정을 더 유연하게 커스터마이징 가능하도록 개선
- PhotoCardList에서 첫 4개 이미지는 eager loading 적용하여 초기 로딩 성능 개선
- ClubDetailPage에서 매직 넘버를 상수로 추출하고 불필요한 주석 코드 제거
- 불필요한 React import 제거
- LazyImage를 common에서 PhotoList 컴포넌트 내부로 이동하여 응집도 향상
- inline style을 styled-components로 리팩토링하여 프로젝트 스타일 가이드 준수
- transient props ($isLoaded, $placeholder) 사용으로 DOM 오염 방지
- PhotoCardList의 import 경로 업데이트
- 테스트 파일도 함께 이동하여 일관성 유지
- IntersectionObserver의 rootMargin 설정을 제거하여 기본값(0px) 사용
- 이미지 로딩 시점을 뷰포트 진입 시점으로 명확히 하여 불필요한 미리 로딩 제거
- 컴포넌트 props 인터페이스 단순화
- 테스트 종속적인 data-testid 속성을 프로덕션 코드에서 제거
- 테스트 코드에서 이미지 부재 여부로 로딩 상태를 검증하도록 수정
- 테스트 설명 문구를 평서문으로 통일 ('~함' -> '~한다')
- 불필요한 타이머 모킹(fake timers) 제거
- LazyImage 컴포넌트의 placeholder 기본값 상수화
@seongwon030 seongwon030 self-assigned this Dec 6, 2025
@seongwon030 seongwon030 added 🔨 Refactor 코드 리팩토링 💻 FE Frontend labels Dec 6, 2025
@vercel
Copy link

vercel bot commented Dec 6, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
moadong Ready Ready Preview Comment Dec 6, 2025 10:28am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • 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

Walkthrough

공통 LazyImage 컴포넌트를 제거하고, 클럽 상세 페이지 전용 LazyImage 컴포넌트를 새로 추가했습니다. 딜레이(100ms)를 제거하고 isEager 플래그로 초기 이미지를 적극 로드하도록 변경했으며 스타일·테스트·PhotoCardList 통합 및 ClubDetailPage의 윈도우 리사이즈 처리 정리를 포함합니다.

Changes

코호트 / 파일(s) 요약
공통 LazyImage 제거
frontend/src/components/common/LazyImage/LazyImage.tsx
기존 공통 LazyImage 컴포넌트 파일 삭제 (default export 제거)
ClubDetailPage 수정
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
MobileWindowWidth 상수 도입(500), 헤더 표시 로직과 리사이즈 핸들러에서 상수 사용, 리사이즈 이벤트 정리 추가
클럽 상세 전용 LazyImage 추가
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
IntersectionObserver 기반 지연 로딩 재구현, 100ms 지연 제거, props: src, alt, onError, placeholder, threshold, isEager, isEager로 즉시 로드 제어, isVisible/isLoaded 상태 관리, default export 추가
LazyImage 스타일링 추가
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.styles.ts
ImageContainer, StyledImage styled-components 추가: 로딩 상태에 따른 배경·투명도 전환(0.3s)
LazyImage 테스트 업데이트
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx
테스트 리팩토링: 100ms 타이머 제거, IntersectionObserver 동작 검증 유지, 설명 한국어화 및 에러 핸들링 검증 방식 조정
PhotoCardList 통합 변경
frontend/src/pages/ClubDetailPage/components/PhotoList/PhotoCardList/PhotoCardList.tsx
LazyImage import 경로를 클럽 상세 페이지 전용으로 변경, IMAGE_EAGER_LOADING_COUNT = 4 도입, index < 4인 항목에 isEager 전달

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • 주의할 파일/포인트:
    • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx의 IntersectionObserver 생성/해제 및 isEager 초기화 로직
    • 이미지 로드 흐름: loading 속성('eager' vs 'lazy')과 isVisible/isLoaded 상태 일치성
    • 테스트(LazyImage.test.tsx)에서 IntersectionObserver 시뮬레이션과 에러/언마운트 검증 적절성
    • PhotoCardList에서 isEager 전달 조건과 import 경로 변경으로 인한 번들 영향
    • ClubDetailPage의 resize 이벤트 cleanup이 누락되지 않았는지

Possibly related issues

  • MOA-401: LazyImage 컴포넌트 로직 개선 — 본 PR은 지연 로딩 딜레이 제거 및 지연 로딩 기준 재설정 목적과 일치합니다.
  • [refactor] MOA-401 LazyImage 컴포넌트 로직 개선 #907: 공통 LazyImage의 지연로딩 로직 변경 관련 — 100ms 딜레이 제거 및 lazy/eager 동작 변경과 관련됩니다.

Possibly related PRs

Suggested reviewers

  • oesnuj

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 LazyImage 컴포넌트 기능 개선 및 성능 최적화라는 주요 변경사항을 명확하게 반영하고 있으며, 실제 코드 변경 내용(setTimeout 제거, isEager prop 추가, 로드 최적화)과 일치합니다.
Linked Issues check ✅ Passed PR 변경사항이 MOA-401의 모든 요구사항을 충족합니다: setTimeout 제거로 불필요한 딜레이 제거, isEager prop 추가로 지연로딩 기준 재설정, ImageEagerLoadingCount=4로 로딩 로직 개선되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 MOA-401의 범위 내에 있습니다. ClubDetailPage의 MobileWindowWidth 상수 도입 및 리스너 정리는 컴포넌트 최적화의 일부이며, 테스트 리팩토링도 LazyImage 개선에 맞춰 적절하게 조정되었습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/#907-improve-lazy-image-MOA-401

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

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 1

🧹 Nitpick comments (3)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)

19-20: 상수 명명 규칙 검토 필요

매직 넘버를 상수로 추출한 점은 좋습니다. 다만, 일반적인 JavaScript/TypeScript 컨벤션에서 상수는 MOBILE_WINDOW_WIDTH (UPPER_SNAKE_CASE)로 작성하는 것이 권장됩니다. PascalCase는 주로 컴포넌트나 클래스에 사용됩니다.

-const MobileWindowWidth = 500;
+const MOBILE_WINDOW_WIDTH = 500;
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx (1)

41-46: isEager prop에 대한 테스트 케이스 추가 고려

현재 테스트는 기본 lazy loading 동작만 검증합니다. isEager={true} 케이스에 대한 테스트를 추가하면 새로운 기능의 동작을 보장할 수 있습니다.

it('isEager가 true일 때 이미지가 즉시 렌더링되어야 한다', () => {
  render(<LazyImage {...defaultProps} isEager={true} />);

  const img = screen.getByRole('img');
  expect(img).toBeInTheDocument();
  expect(img).toHaveAttribute('src', 'test-image.jpg');
});
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx (1)

49-61: loading 속성과 IntersectionObserver 중복 고려

loading="lazy" 속성은 브라우저 네이티브 lazy loading을 활성화합니다. 현재 구현에서는 IntersectionObserver로 이미 visibility를 제어하므로, 이미지가 렌더링될 때는 이미 viewport 내에 있어 loading="lazy"가 실질적인 효과가 없을 수 있습니다.

의도적인 fallback 전략이라면 현재 구현을 유지해도 무방합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9cb7bf4 and cf084d7.

📒 Files selected for processing (6)
  • frontend/src/components/common/LazyImage/LazyImage.tsx (0 hunks)
  • frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1 hunks)
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.styles.ts (1 hunks)
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx (2 hunks)
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx (1 hunks)
  • frontend/src/pages/ClubDetailPage/components/PhotoList/PhotoCardList/PhotoCardList.tsx (3 hunks)
💤 Files with no reviewable changes (1)
  • frontend/src/components/common/LazyImage/LazyImage.tsx
🧰 Additional context used
📓 Path-based instructions (3)
frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries with if/else or IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling

Files:

  • frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.styles.ts
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/PhotoCardList/PhotoCardList.tsx
frontend/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

frontend/**/*.{tsx,jsx}: Abstract complex logic/interactions into dedicated components/HOCs
Separate significantly different conditional UI/logic into distinct components
Colocate simple, localized logic or use inline definitions to reduce context switching
Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Use Component Composition instead of Props Drilling to reduce coupling

Files:

  • frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/PhotoCardList/PhotoCardList.tsx
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

Use consistent return types for similar functions/hooks

Files:

  • frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.styles.ts
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx
  • frontend/src/pages/ClubDetailPage/components/PhotoList/PhotoCardList/PhotoCardList.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
📚 Learning: 2025-03-19T05:18:07.818Z
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.

Applied to files:

  • frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
📚 Learning: 2025-11-25T14:08:23.253Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-11-25T14:08:23.253Z
Learning: Applies to frontend/**/*.{ts,tsx,js,jsx} : Replace magic numbers with named constants for clarity

Applied to files:

  • frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
🧬 Code graph analysis (1)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)
frontend/src/hooks/queries/club/useGetClubDetail.ts (1)
  • useGetClubDetail (6-20)
🔇 Additional comments (6)
frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx (1)

28-35: LGTM!

resize 이벤트 리스너에 cleanup 함수가 올바르게 구현되어 메모리 누수를 방지합니다.

frontend/src/pages/ClubDetailPage/components/PhotoList/PhotoCardList/PhotoCardList.tsx (2)

11-12: LGTM!

매직 넘버 4IMAGE_EAGER_LOADING_COUNT 상수로 추출하여 코드 가독성을 높였습니다. PR 목표에 맞게 데스크탑/태블릿/모바일 공통으로 4개 기준을 적용했습니다.


21-34: LGTM!

isEager prop을 인덱스 기반으로 전달하여 초기 렌더링 시 보이는 이미지들은 즉시 로딩되도록 구현했습니다. 기존 에러 처리 로직도 유지됩니다.

frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.styles.ts (1)

1-18: LGTM!

Transient props ($isLoaded, $placeholder)를 올바르게 사용하여 DOM에 불필요한 속성이 전달되지 않도록 했습니다. 0.3s 트랜지션으로 부드러운 로딩 효과를 제공합니다.

frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.test.tsx (1)

57-75: LGTM!

IntersectionObserver 콜백 호출 시 이미지가 로드되고, observer가 disconnect되는 동작을 올바르게 검증합니다. 100ms setTimeout 제거에 맞게 타이머 관련 코드도 제거되었습니다.

frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx (1)

28-47: LGTM!

PR 목표에 맞게 100ms setTimeout이 제거되어 IntersectionObserver 감지 즉시 setIsVisible(true)가 호출됩니다. isEager 시 early return으로 불필요한 observer 생성을 방지하고, cleanup 함수로 메모리 누수를 방지합니다.

@seongwon030 seongwon030 added the ✅ Test test 관련(storybook, jest...) label Dec 6, 2025
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: 0

🧹 Nitpick comments (1)
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx (1)

48-61: 렌더링 로직 검토 및 선택적 리팩토링 제안

전반적인 구현은 정확하지만, Line 56의 loading 속성 사용이 약간 중복됩니다:

  • isEager=true일 때: loading="eager" ✅ 즉시 고우선순위 로딩
  • isEager=false일 때: IntersectionObserver가 이미 지연 로딩을 처리했고, <img> 엘리먼트가 viewport에 있을 때만 생성되므로 loading="lazy"는 실질적 효과가 없습니다.

더 명확한 접근 방식:

-          loading={isEager ? 'eager' : 'lazy'}
+          loading="eager"

또는 의도를 명확히 하기 위해 조건부로:

-          loading={isEager ? 'eager' : 'lazy'}
+          loading={isEager ? 'eager' : 'eager'}

설명: IntersectionObserver가 "언제 로드할지"를 결정하고 나면, 브라우저에게 즉시 로드하도록 지시하는 것이 더 일관성 있습니다. 현재 구현도 동작하지만, 두 가지 지연 로딩 메커니즘(IntersectionObserver + 네이티브 lazy loading)이 혼재되어 약간 혼란스러울 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cf084d7 and 377980b.

📒 Files selected for processing (1)
  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
frontend/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

frontend/**/*.{ts,tsx,js,jsx}: Replace magic numbers with named constants for clarity
Replace complex/nested ternaries with if/else or IIFEs for readability
Assign complex boolean conditions to named variables for explicit meaning
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle)
Use unique and descriptive names for custom wrappers/functions to avoid ambiguity
Define constants near related logic or ensure names link them clearly to avoid silent failures
Break down broad state management into smaller, focused hooks/contexts to reduce coupling

Files:

  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
frontend/**/*.{tsx,jsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

frontend/**/*.{tsx,jsx}: Abstract complex logic/interactions into dedicated components/HOCs
Separate significantly different conditional UI/logic into distinct components
Colocate simple, localized logic or use inline definitions to reduce context switching
Choose field-level or form-level cohesion based on form requirements when using form libraries like react-hook-form
Use Component Composition instead of Props Drilling to reduce coupling

Files:

  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

Use consistent return types for similar functions/hooks

Files:

  • frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: seongwon030
Repo: Moadong/moadong PR: 195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
🔇 Additional comments (5)
frontend/src/pages/ClubDetailPage/components/PhotoList/LazyImage/LazyImage.tsx (5)

1-2: LGTM!

필요한 의존성만 깔끔하게 import하고 있습니다.


4-11: LGTM!

인터페이스 정의가 명확하고, 이전 리뷰에서 지적된 미사용 rootMargin prop이 제거되었습니다. isEager prop 추가로 PR 목표가 잘 반영되었습니다.


13-13: LGTM!

매직 문자열을 명명된 상수로 추출하여 코드 가독성과 유지보수성을 개선했습니다.


15-25: LGTM!

isVisible 상태를 isEager 값으로 초기화하는 것은 효율적인 최적화입니다. eager 이미지는 IntersectionObserver 설정 없이 즉시 렌더링됩니다.


27-46: LGTM!

IntersectionObserver 로직이 PR 목표를 완벽하게 달성했습니다:

  • ✅ 100ms setTimeout 제거: 교차 감지 즉시 setIsVisible(true) 호출
  • isEager 플래그 지원: eager 이미지는 observer 설정 생략
  • ✅ 적절한 cleanup과 의존성 관리

@seongwon030 seongwon030 requested a review from lepitaaar December 6, 2025 10:35
Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

좋은코드 잘봤습니다

@lepitaaar lepitaaar merged commit 96099da into develop-fe Dec 7, 2025
3 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Dec 7, 2025
@seongwon030 seongwon030 linked an issue Dec 8, 2025 that may be closed by this pull request
1 task
@seongwon030 seongwon030 deleted the refactor/#907-improve-lazy-image-MOA-401 branch December 17, 2025 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend 🔨 Refactor 코드 리팩토링 ✅ Test test 관련(storybook, jest...)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[refactor] MOA-401 LazyImage 컴포넌트 로직 개선

2 participants