
스크롤 값을 이용하여 시각적으로 자연스러운 웹사이트를 만들 수 있다.
window 객체를 이용하여 현재 위치를 알 수 있다.
window.addEventListener("scroll", ()=> { console.log(window.scrollY) })
React의 useEffect를 이용하여 이를 state화 시키면 React에서 사용자의 scroll 위치를 이용할 수 있다.
const [scrollY, setScrollY] = useState(0);
useEffect(() => {
const handleScroll = () => {
setScrollY(window.scrollY);
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
이를 이용해 스크롤에 따라 스타일이 변하는 컴포넌트를 만들 수 있다. 나는 스크롤이 최상단에 있을 때 크기가 커지는 Navigation Bar 를 만들었다.

<Wrapper istop={scrollY === 0}>
...
</Wrapper>
const Wrapper = styled.div<{ istop: boolean }>`
height: ${(props) => (props.istop ? "80px" : "60px")};
`;
React의 useRef의 scrollIntoView를 이용하여 특정 컴포넌트로 스크롤을 이동시킬 수 있다.
const boxRef = useRef<HTMLDivElement>(null);
const onClick = () => {
boxRef.current?.scrollIntoView({ behavior: "smooth" });
};
...
<Box ref={boxRef} />
<Button onClick={onClick}>Box로 이동</Button>
https://developer.mozilla.org/ko/docs/Web/API/Element/scrollIntoView
컴포넌트의 위치(위, 아래, 중앙 등)나 스크롤 속도(smooth, instant)등을 설정할 수 있다.
이를 이용하여 특정 컴포넌트로 이동시켜주는 Navigaton Bar를 만들 수 있다.

const portfolioRef = useRef<HTMLDivElement>(null);
const onPortfolioClick = () => {
portfolioRef.current?.scrollIntoView({ behavior: "smooth"!
});
};
<Content onClick={onPortfolioClick}>PORTFOLIO</Content>
...
<Portfolios ref={portfolioRef} />
block : "center"를 이용해 주면 컴포넌트의 중앙으로 이동할 수 도 있다.

const portfolioRef = useRef<HTMLDivElement>(null);
const onPortfolioClick = () => {
portfolioRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
};
<Content onClick={onPortfolioClick}>PORTFOLIO</Content>
...
<Portfolios ref={portfolioRef} />
내가 생각한 방법은
이었는데 _useRef를 이용하여 컴포넌트의 scrollY 값 가져오기_가 되지 않아 어려움이 있었다.
내가 원했던 기능은 특정 컴포넌트에 다다르면 Navigation Bar에서 이를 확인할 수 있게 하는 것이었기 때문에 컴포넌트의 수가 많지 않았고, 위에서 부터 컴포넌트의 scrollHeight를 다 더해가는 식으로 구현하였다.
useEffect(() => {
if (scrollY < mainRef.current?.scrollHeight + 300) setIsnow(0);
else if (
scrollY > mainRef.current?.scrollHeight + 300 &&
scrollY < mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + 300) setIsnow(1);
else if (
scrollY > mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + 300 &&
scrollY < mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + blogRef.current.scrollHeight + 300) setIsnow(2);
else if ( scrollY > mainRef.current?.scrollHeight + portFolioRef.current.scrollHeight + blogRef.current.scrollHeight + 300 ) setIsnow(3);
}, [scrollY]);
...
<MainContent ref={mainRef} />
<Projects ref={portfolioRef} />
<Blog ref={blogRef} />
<Contact ref={contactRef} />
컴포넌트는 위에서 부터 다음과 같이 배치되어 있다.
Main 높이 < scrollY < Main 높이 + Portfolio 높이 이면 isnow를 변경하여 Portfolio에 있다고 하는 식으로 구현하였다.
마지막으로 Navigation Bar에 isnow를 이용하여 스타일을 변화해 주었다.
<Content onClick={onBlogClick}>BLOG{isnow === 2 && <UnderBar />}</Content>

특정 컴포넌트로 이동시키는게 목적이 아니라면 window의 scrollTo()를 이용하면 된다.
<Button onClick={() => { window.scrollTo(0, 0); }}>BACK TO TOP</Button>
