Intro
์๋ ํ์ธ์. React์์ window.scroll ์ด๋ฒคํธ๊ฐ ์ ๋๋ก ์๋ํ์ง ์์ ์๋ฌ๊ฐ ๋ฐ์ํ์์ต๋๋ค. ์๋ฌด๋ฆฌ window.scrollY ๊ฐ์ ๊ตฌํด๋ 0์ผ๋ก ๋์ค๋๋ผ๊ณ ์.
์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
// state
const [scrollTop, setScrollTop] = useState(0),
headerRef = useRef<HTMLDivElement>(null),
headerHeight = headerRef?.current?.clientHeight ?? 0,
// useEffect
useEffect(() => {
const handleScroll = () => {
setScrollTop(window.scrollY);
};
handleScroll();
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
// rendering
<section style={{right: handlePositionState}} ref={bottomSheetRef}>
<div className={scrollTop > headerHeight ? `${styles.tabArea} ${styles.active}` : styles.tabArea}>
....
</div>
</section>
ํน์ ๋ฒํผ์ ๋๋ ์ ๋ ํด๋น ์ปดํฌ๋ํธ๊ฐ ํ์ ๋จ๋ ํํ์์ต๋๋ค. ๋ถ๋ชจ component์๋ scroll์ด ์๊ณ , ํ์ ์ปดํฌ๋ํธ์๋ scroll์ด ์์์ต๋๋ค. ํ์ ์ปดํฌ๋ํธ๊ฐ ์ด๋ฆฌ๋ ์๊ฐ ํ์ ์ปดํฌ๋ํธ์ ๋ถ๋ชจ์ ์คํฌ๋กค์ ์ํฅ์ ๋ฐ์ง ์๊ธฐ ์ํด body์ overflow: hidden; height: 100vh; ๋ฅผ ์ถ๊ฐํ์ด์.
์ดํ ํ์ ์ปดํฌ๋ํธ ์์์ ํน์ ์คํฌ๋กค ์์น์ ๋๋ฌํ๋ฉด css ํจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์ํด window.scrollY๊ฐ์ด ํ์ํ์ต๋๋ค. ํ์ง๋ง window.scrollY ์ด ๊ณ์ 0์ผ๋ก ๋์ค๋๋ผ๊ณ ์.
Why?
๊ตฌ๊ธ๋ง ๊ฒ์ ๊ฒฐ๊ณผ body์ overflow:hidden ์ ์ญ์ ํ๋ฉด ์ ๋๋ก ์๋ํ๋ค๋ ๋ด์ฉ์ ์ฐพ์์ต๋๋ค. ํ์ง๋ง ์ ์ผ์ด์ค์ ๊ฒฝ์ฐ hidden์ ์ญ์ ํ๋ฉด ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ์คํฌ๋กค์ด ๋ณด์ฌ์ง๊ธฐ ๋๋ฌธ์ ๊ทธ๋ด ์ ์์์ต๋๋ค. ์ด ์ธ์๋ scrollHeight, clientHeight ๋ฑ ๋ค๋ฅธ ์์ฑ๋ ์ฌ์ฉํด๋ดค์ง๋ง ๊ฒฐ๊ณผ๋ ๋๊ฐ์์ต๋๋ค.
How to solve problem
window ๊ฐ์ฒด๊ฐ ์๋ useRef๋ฅผ ์ฌ์ฉํ์ฌ ํด๋น ์ปดํฌ๋ํธ์ ์ต์์ ๋์ด๋ฅผ ๊ตฌํ์ฌ ์๋์ ๊ฐ์ด ํ์ฉํ๋ scroll handler๊ฐ ์ ๋๋ก ์๋ํ์์ต๋๋ค.
const bottomSheetRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const handleScroll = () => {
setScrollTop(bottomSheetRef?.current?.scrollTop ?? 0);
};
handleScroll();
bottomSheetRef?.current?.addEventListener('scroll', handleScroll);
return () => {
bottomSheetRef?.current?.removeEventListener('scroll', handleScroll);
};
}, []);
ํน์ React์์ ์ ์ ๊ฐ์ ์ํฉ์ด์ ๋ถ๋ค์ด ๊ณ์๋ค๋ฉด ์ ๋ฐฉ๋ฒ์ ํ๋ฒ ํ์ฉํด๋ณด์๊ธธ ๋ฐ๋๋๋ค :)