[feature] 스크롤 트리거 훅과 스크롤 상단 이동 버튼 추가#800
Conversation
- useScrollToTop 훅 추가 (500px 이상 스크롤 시 버튼 표시) - ScrollButton 컴포넌트 추가 (styled-components 사용) - App.tsx에 전역 적용하여 모든 페이지에서 사용 가능 - 부드러운 opacity 전환 효과 적용 - 접근성 개선 (aria-label 추가)
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| 응집군 / 파일(들) | 변경 요약 |
|---|---|
스크롤 감지 훅 frontend/src/hooks/useScrollTrigger.ts |
스크롤 위치 및 방향을 감지하는 커스텀 React 훅 추가. threshold, direction('up'|'down'), passive 옵션과 onChange 콜백 지원. isTriggered 상태 반환. |
스크롤 상단 버튼 스타일링 frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.styles.ts |
styled-components를 사용한 ScrollButton 컴포넌트 추가. $isVisible prop으로 가시성 제어 (opacity 전환 0.3초), 고정 위치(bottom-right), 스타일링 포함. |
스크롤 상단 버튼 컴포넌트 frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.tsx |
스크롤 아이콘과 styled 버튼을 사용하는 React 컴포넌트. useScrollTrigger 훅으로 가시성 제어, 클릭 시 window.scrollTo() 실행. 한글 aria-label 포함. |
App 통합 frontend/src/App.tsx |
ScrollToTopButton 컴포넌트 import 및 GlobalStyles 아래에 JSX 추가. |
시퀀스 다이어그램
sequenceDiagram
participant User
participant ScrollToTopButton
participant useScrollTrigger
participant Browser
User->>Browser: 페이지 스크롤
Browser->>useScrollTrigger: scroll 이벤트 발생
useScrollTrigger->>useScrollTrigger: scrollY와 threshold 비교
useScrollTrigger->>ScrollToTopButton: isTriggered 상태 업데이트
ScrollToTopButton->>ScrollToTopButton: $isVisible prop으로 버튼 표시/숨김
User->>ScrollToTopButton: 버튼 클릭
ScrollToTopButton->>Browser: window.scrollTo(0, 0) 실행
Browser->>User: 페이지 최상단으로 스크롤
예상 코드 리뷰 난이도
🎯 2 (단순) | ⏱️ ~10분
- 주의 사항:
useScrollTrigger훅의 scroll 이벤트 리스너 정리(cleanup) 로직 확인 필요- passive 옵션의 성능 영향 검토
- $isVisible prop 전환 시 애니메이션 부드러움 확인
- 접근성: aria-label 한글 표기 적절성 확인
관련 이슈
- MOA-297: 스크롤 상단 이동 훅과 버튼을 추가하는 요구사항을 구현하는 PR. 이 변경 사항이 해당 이슈의 목표를 직접적으로 충족합니다.
제안 검토자
- seongje973
- oesnuj
Pre-merge checks and finishing touches
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목은 '[feature] 스크롤 트리거 훅과 스크롤 상단 이동 버튼 추가'로, 핵심 변경사항인 useScrollTrigger 훅과 ScrollToTopButton 컴포넌트 추가를 정확히 요약합니다. |
| Linked Issues check | ✅ Passed | 모든 연결된 이슈 요구사항이 충족됩니다: (1) useScrollTrigger 훅 구현 완료 - threshold, direction, passive, onChange 옵션 지원 MOA-297, (2) ScrollToTopButton 컴포넌트와의 연동 완료 - 훅의 isTriggered 값으로 버튼 표시/비표시 제어, 클릭 시 window.scrollTo로 상단 이동 MOA-297. |
| Out of Scope Changes check | ✅ Passed | 모든 변경사항이 MOA-297 이슈 범위 내에 있습니다. 스크롤 훅, 스타일 컴포넌트, ScrollToTopButton 컴포넌트, App.tsx 통합 등의 변경사항은 모두 스크롤 상단 이동 기능 구현이라는 명확한 목표와 직결됩니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✨ 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
feature/#799-scroll-to-top-hook-and-button-MOA-297
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
frontend/src/hooks/useScrollToTop.ts (1)
14-17: useEffect 의존성 배열에 handleScroll을 추가하세요.
handleScroll함수가 useEffect 의존성 배열에 포함되어 있지 않습니다. React 19에서는 이로 인해 경고가 발생할 수 있습니다. 함수를 useCallback으로 메모이제이션하거나 의존성 배열에 추가하는 것이 좋습니다.다음 두 가지 해결 방법 중 하나를 선택하세요:
방법 1 (권장): useCallback 사용
+import { useEffect, useState, useCallback } from "react"; export const useScrollToTop = () => { const [isVisibleButton, setIsVisibleButton] = useState(false); - const handleScroll = () => { + const handleScroll = useCallback(() => { setIsVisibleButton(window.scrollY > SCROLL_THRESHOLD); - } + }, []); useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); - }, []); + }, [handleScroll]);방법 2: useEffect 내부에서 함수 정의
useEffect(() => { + const handleScroll = () => { + setIsVisibleButton(window.scrollY > SCROLL_THRESHOLD); + }; + window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); - - const handleScroll = () => { - setIsVisibleButton(window.scrollY > SCROLL_THRESHOLD); - }
📜 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.
⛔ Files ignored due to path filters (1)
frontend/src/assets/images/icons/scroll.pngis excluded by!**/*.png
📒 Files selected for processing (3)
frontend/src/App.tsx(2 hunks)frontend/src/components/common/Button/scrollButton.tsx(1 hunks)frontend/src/hooks/useScrollToTop.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/App.tsxfrontend/src/hooks/useScrollToTop.tsfrontend/src/components/common/Button/scrollButton.tsx
frontend/**/*.tsx
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order 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.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.
Files:
frontend/src/App.tsxfrontend/src/components/common/Button/scrollButton.tsx
🧠 Learnings (4)
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Applied to files:
frontend/src/App.tsx
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Separate significantly different conditional UI/logic into distinct components.
Applied to files:
frontend/src/App.tsx
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use consistent return types for similar functions and hooks.
Applied to files:
frontend/src/hooks/useScrollToTop.ts
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.tsx : Break down broad state management into smaller, focused hooks or contexts.
Applied to files:
frontend/src/hooks/useScrollToTop.ts
🧬 Code graph analysis (2)
frontend/src/App.tsx (1)
frontend/src/components/common/Button/scrollButton.tsx (1)
ScrollButton(25-38)
frontend/src/components/common/Button/scrollButton.tsx (1)
frontend/src/hooks/useScrollToTop.ts (1)
useScrollToTop(3-27)
🔇 Additional comments (3)
frontend/src/App.tsx (1)
22-22: ScrollButton 통합이 잘 되었습니다!전역 UI 요소로서 적절한 위치에 배치되었으며, 모든 라우트에서 사용할 수 있도록 구현되었습니다.
Also applies to: 31-31
frontend/src/components/common/Button/scrollButton.tsx (1)
25-38: 접근성이 잘 고려된 구현입니다!
aria-label과alt텍스트가 적절히 제공되어 있어 스크린 리더 사용자도 버튼의 기능을 이해할 수 있습니다.frontend/src/hooks/useScrollToTop.ts (1)
19-24: moveToTop 함수 구현이 잘 되었습니다!
window.scrollTo를 사용하여 부드러운 스크롤 애니메이션이 적용되어 사용자 경험이 좋습니다.
- 스크롤 상단 이동 버튼 표시 임계값을 상수 SCROLL_TO_TOP_THRESHOLD로 변경하여 가독성 향상
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
frontend/src/hooks/useScrollToTop.ts (1)
8-14: 조건문을 단순화하고useCallback으로 메모이제이션하세요.두 가지 개선이 필요합니다:
- if/else 조건문을 단일 표현식으로 단순화할 수 있습니다.
handleScroll이 메모이제이션되지 않아 매 렌더마다 새로운 함수가 생성됩니다. 이는 useEffect 의존성 배열 문제를 야기할 수 있습니다.다음 diff를 적용하세요:
+import { useEffect, useState, useCallback } from "react"; - const handleScroll = () => { - if (window.scrollY > SCROLL_TO_TOP_THRESHOLD) { - setIsVisibleButton(true); - } else { - setIsVisibleButton(false); - } - } + const handleScroll = useCallback(() => { + setIsVisibleButton(window.scrollY > SCROLL_TO_TOP_THRESHOLD); + }, []);As per coding guidelines.
📜 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.
📒 Files selected for processing (1)
frontend/src/hooks/useScrollToTop.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
frontend/**/*.{ts,tsx}
📄 CodeRabbit inference engine (frontend/.cursorrules)
frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.
Files:
frontend/src/hooks/useScrollToTop.ts
🧠 Learnings (2)
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Use consistent return types for similar functions and hooks.
Applied to files:
frontend/src/hooks/useScrollToTop.ts
📚 Learning: 2025-07-19T05:09:10.702Z
Learnt from: CR
Repo: Moadong/moadong PR: 0
File: frontend/.cursorrules:0-0
Timestamp: 2025-07-19T05:09:10.702Z
Learning: Applies to frontend/**/*.{ts,tsx} : Replace magic numbers with named constants for clarity.
Applied to files:
frontend/src/hooks/useScrollToTop.ts
🔇 Additional comments (3)
frontend/src/hooks/useScrollToTop.ts (3)
3-3: 상수 정의가 잘 되었습니다.매직 넘버를
SCROLL_TO_TOP_THRESHOLD상수로 교체한 것이 좋습니다.As per coding guidelines.
16-19: 의존성 배열 검증 필요.
useEffect가handleScroll을 사용하지만 의존성 배열에 포함되지 않았습니다. 위에서 제안한useCallback으로handleScroll을 메모이제이션하면 이 문제가 해결되며,handleScroll을 의존성 배열에 추가해야 합니다.다음 diff를 적용하세요:
useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); - }, []); + }, [handleScroll]);As per coding guidelines.
28-28: 반환 구조가 명확합니다.일관된 반환 타입으로
isVisibleButton과moveToTop을 반환하는 것이 좋습니다.As per coding guidelines.
그래서 안 겹치도록 디자인 수정해 주실 것 같네요! |
suhyun113
left a comment
There was a problem hiding this comment.
상단으로 이동하는 버튼이 자연스럽게 잘 생기고 이동도 잘 되는 것 같아요!
수고하셨습니다ㅏ👍
- 스크롤 이벤트 핸들러에 passive: true 옵션을 추가하여 스크롤 성능을 최적화 - preventDefault()를 사용하지 않으므로 passive 옵션으로 브라우저의 스크롤 렌더링을 블로킹하지 않도록 개선
oesnuj
left a comment
There was a problem hiding this comment.
상단 이동 버튼 추가 좋습니다😊 스무스하게 움직여서 재밌네요 ㅋㅋㅋ
코드 보면서 코멘트 몇개 남겨두었어요 확인 부탁드려요 :)
- useScrollToTop 훅 생성으로 스크롤 감지 로직 분리 - ScrollButton 컴포넌트 구현 - 스크롤 아이콘 추가
- common/ScrollButon 폴더 아래로 분리
- Button/scrollButton.tsx → ScrollButton/ScrollButton.tsx로 이동 - 스크롤 감지 로직을 useScrollToTop 훅으로 분리 - isTriggered 상태를 훅에서 관리하도록 변경
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
frontend/src/hooks/useScrollToTop.ts (1)
12-12: 기본threshold값이 너무 낮습니다.기본값
10px은 사용자가 아주 조금만 스크롤해도 버튼이 나타나게 합니다. 일반적으로 300~500px 정도가 적절합니다.과거 리뷰에서도 언급되었듯이, 적절한 threshold 값에 대해 팀 논의가 필요합니다.
🧹 Nitpick comments (2)
frontend/src/components/common/ScrollButton/ScrollButton.tsx (2)
6-11: 훅 호출 시threshold값 명시를 고려하세요.
useScrollToTop()을 기본값으로 호출하면threshold=10으로 설정되어 사용자가 아주 조금만 스크롤해도 버튼이 나타납니다. 과거 리뷰 코멘트에서도 이 값에 대한 논의가 필요하다고 언급되었습니다.UX 관점에서 적절한 threshold 값(예: 300~500px)을 명시적으로 전달하는 것을 권장합니다.
다음과 같이 수정할 수 있습니다:
- const { isTriggered } = useScrollToTop(); + const { isTriggered } = useScrollToTop({ threshold: 300 });
13-22: 구현이 잘 되었습니다!컴포넌트 구조가 깔끔하고 접근성 속성(
aria-label)도 적절히 설정되어 있습니다.한 가지 사소한 개선 사항:
alt텍스트가 영어로 되어 있는데,aria-label과 일관되게 한국어로 통일하는 것도 고려해보세요.- <img src={scrollButtonIcon} alt="Scroll to top" /> + <img src={scrollButtonIcon} alt="맨 위로 이동" />
📜 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.
⛔ Files ignored due to path filters (1)
frontend/src/assets/images/icons/scroll_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (4)
frontend/src/App.tsx(2 hunks)frontend/src/components/common/ScrollButton/ScrollButton.styles.ts(1 hunks)frontend/src/components/common/ScrollButton/ScrollButton.tsx(1 hunks)frontend/src/hooks/useScrollToTop.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/App.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/common/ScrollButton/ScrollButton.tsx (1)
frontend/src/hooks/useScrollToTop.ts (1)
useScrollToTop(11-38)
frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.styles.ts
Show resolved
Hide resolved
- useCallback 적용으로 handleScroll 함수 재생성 방지 - 함수형 업데이트로 클로저 문제 및 무한 루프 방지 - 의존성 배열에서 isTriggered 제거하여 이벤트 리스너 재등록 방지 - useScrollToTop -> useScrollTrigger로 변경
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
frontend/src/hooks/useScrollTrigger.ts (1)
11-39: JSDoc 문서화 추가 권장훅의 사용법과 각 옵션의 의미를 명확히 하기 위해 JSDoc 주석을 추가하는 것을 권장합니다.
+/** + * 스크롤 위치에 따라 트리거 상태를 추적하는 커스텀 훅 + * + * @param options - 스크롤 트리거 옵션 + * @param options.threshold - 트리거가 활성화되는 스크롤 임계값 (픽셀, 기본값: 10) + * @param options.direction - 트리거 방향 ('down': 임계값보다 아래로 스크롤, 'up': 임계값보다 위로 스크롤, 기본값: 'down') + * @param options.passive - 패시브 이벤트 리스너 사용 여부 (기본값: true) + * @param options.onChange - 트리거 상태 변경 시 호출될 콜백 (메모이제이션 권장) + * @returns 트리거 활성화 여부를 나타내는 isTriggered 상태 + * + * @example + * const { isTriggered } = useScrollTrigger({ + * threshold: 100, + * direction: 'down' + * }); + */ export const useScrollTrigger = ({
📜 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.
📒 Files selected for processing (2)
frontend/src/components/common/ScrollButton/ScrollButton.tsx(1 hunks)frontend/src/hooks/useScrollTrigger.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/components/common/ScrollButton/ScrollButton.tsx
🔇 Additional comments (3)
frontend/src/hooks/useScrollTrigger.ts (3)
1-8: LGTM! 타입 정의가 명확합니다.임포트와 인터페이스 정의가 적절하며,
ScrollTriggerOptions의 타입이 명확하고 안전하게 정의되어 있습니다.
11-16: LGTM! 훅 시그니처가 적절합니다.기본값 설정과 구조 분해 패턴이 올바르게 구현되어 있으며, 파라미터 없이 호출 가능하도록 설계되었습니다.
33-36: LGTM! 이벤트 리스너 관리가 적절합니다.스크롤 이벤트 리스너의 등록과 정리가 올바르게 구현되었으며,
passive옵션을 통한 성능 최적화도 적용되어 있습니다.
- 폴더, 파일명 모두 변경
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.styles.ts (1)
3-21: z-index와 위치 하드코딩은 기존 레이아웃/알림톡과의 겹침을 다시 한 번 점검해 주세요.
position: fixed+bottom: 80px; right: 30px; z-index: 1000;조합이면, PR 코멘트에서 언급된 알림톡/기타 고정 요소와 실제 화면에서 겹치지 않는지 확인이 필요합니다.- 특히 여러 고정 요소(헤더, 모달, 알림 등)가 이미
z-index: 1000근처 값을 쓰고 있다면, 공용 z-index 스케일(예:constants/zIndex.ts같은 곳에 계층별 상수 정의)을 두고 여기서는 해당 상수를 사용하는 방향이 더 안전합니다.- 모바일 뷰포트에서는
bottom: 80px여백이 과하거나 다른 컴포넌트를 가릴 수 있어, 간단한 media query로 하단/우측 여백만 줄이는 것도 고려해 볼 만합니다.예시:
export const ScrollButton = styled.button<{ $isVisible: boolean }>` position: fixed; - bottom: 80px; - right: 30px; - z-index: 1000; + bottom: 80px; + right: 30px; + z-index: 1000; /* 추후 공용 z-index 상수로 치환 권장 */ @@ padding: 0; + + @media (max-width: 768px) { + bottom: 56px; + right: 16px; + }실제 서비스 주요 화면(알림톡 노출 레이아웃 포함)에서 겹침 여부를 한번 더 확인해 주세요. 필요하다면 위 예시처럼 break-point 별 하단 여백을 조정하는 방향으로 보완하면 좋겠습니다.
🧹 Nitpick comments (1)
frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.tsx (1)
18-21: 버튼에 aria-label이 있으므로 내부 아이콘은 장식용으로 처리하는 편이 접근성에 더 안전합니다.현재 구조에서는 버튼에
aria-label="위로 이동하기"가 있고, 내부 이미지에alt="Scroll to top"이 있어서 스크린 리더에서 이중으로 읽힐 수 있습니다. 아이콘은 순수 장식용으로 보고 alt를 비우는 쪽을 추천합니다.- <img src={scrollButtonIcon} alt="Scroll to top" /> + <img src={scrollButtonIcon} alt="" aria-hidden="true" />
📜 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.
📒 Files selected for processing (3)
frontend/src/App.tsx(2 hunks)frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.styles.ts(1 hunks)frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/App.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.tsx (1)
frontend/src/hooks/useScrollTrigger.ts (1)
useScrollTrigger(11-39)
🔇 Additional comments (1)
frontend/src/components/common/ScrollToTopButton/ScrollToTopButton.tsx (1)
6-22: 스크롤 트리거 연동과 동작 흐름은 명확합니다.
useScrollTrigger()로 노출 여부를 제어하고, 클릭 시window.scrollTo로 부드럽게 맨 위로 올리는 흐름이 직관적입니다.- 훅의 기본 옵션(threshold, direction 등)을 이 컴포넌트에서는 기본값으로 고정해 두고, 추후 필요 시 상위에서 옵션으로 주입하는 방식으로 확장하기에도 무난해 보입니다.
스크롤이 매우 긴 페이지(콘텐츠 로딩/가상 스크롤 등)에서도 원하는 타이밍에 버튼이 노출되는지 QA 단계에서 한 번 확인해 주세요.
oesnuj
left a comment
There was a problem hiding this comment.
리뷰 코멘트 반영해주신거 좋습니다 🔥
ScrollToTopButton으로 바뀐거 좋습니다~
스크롤 관련 훅도 좀 더 재사용성 좋게 바뀌었네요
#️⃣연관된 이슈
📝작업 내용
useScrollToTop 커스텀 훅
클로저 문제 해결
scrollY계산해서 스크롤버튼을 보여주는
handleScroll함수가 재생성되는 문제가 있었습니다.1. useCallback 적용
handleScroll함수에 useCallback 적용하여 불필요한 함수 재생성을 방지했습니다.2. 함수형 업데이트
useCallback을 사용할 때는 의존성 배열을 설정해야 합니다. 여기에 외부 변수인
isTriggered를 넣는다면 바로바로 상태를 업데이트 할 수 있지만, 외부 변수를 직접 참조합니다.여기서 여러 가지 문제가 일어납니다.
오래된 클로저 (Stale Closure)
만약 의존성 배열이 빈 배열이라면 함수 최초 생성 시 state를 계속 참조하게 됩니다. 그럼 업데이트된 값을 볼 수 없게 됩니다.
무한 재생성
isTriggered가 변경될 때마다 handleScroll이 재생성되기에 스크롤할 때마다 같은 사이클이 반복됩니다. 성능 저하 문제가 생깁니다.⭕️ 함수형 업데이트
setIsTriggered를 함수형 업데이트로 변경했습니다.이렇게 하면
isTriggered를 직접 참조하지 않아 무한 재생성 문제도 없고, prev로 항상 최신값만 보장할 수 있습니다.함수 재생성 테스트
old version

new version

ScrollButton 컴포넌트를 독립 디렉터리로 이동
common/Button/ScrollButton경로에서common/ScrollButton/ScrollButton으로 변경했습니다.스크롤 이미지 변경
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
새로운 기능