728x90
Intersection Observer API는 특정 엘리먼트가 viewport
에 보일 때 관찰할 수 있게 해준다. 주로 페이지 성능 개선을 위해 Lazy Image Loading 등에 사용한다. 하지만 여기서는 Intersection Observer를 사용하지 않고, React와 TypeScript로 비슷한 기능을 직접 구현해보자.
1. 화면 크기 구하기 및 이벤트 감지
엘리먼트가 화면에 보이는지 관찰하려면, 먼저 window
의 width
, height
를 알아야 한다. 화면 크기가 변할 때마다 관찰 함수를 실행하도록 resize
이벤트 핸들러를 추가한다. 또한, 스크롤이 발생할 때도 엘리먼트 위치를 재확인해야 하므로 scroll
이벤트 핸들러도 등록한다.
// useEffect 예시
useEffect(() => {
handleObserveElement();
}, [handleObserveElement]);
useEffect(() => {
window.addEventListener('resize', handleObserveElement);
return () => {
window.removeEventListener('resize', handleObserveElement);
};
}, [handleObserveElement]);
useEffect(() => {
window.addEventListener('scroll', handleObserveElement);
return () => {
window.removeEventListener('scroll', handleObserveElement);
};
}, [handleObserveElement]);
2. handleObserveElement 함수 작성
요소가 화면에 보이는지 판단하는 핵심 함수다.
현재 뷰포트 크기를 구하고, 관찰 대상 엘리먼트의 위치를 getBoundingClientRect()
로 구한다.
엘리먼트의 Y좌표가 화면 높이보다 작으면 (즉, 화면 안에 들어오면) isViewing
상태를 true
로 변경한다.
const [isViewing, setIsViewing] = useState<boolean>(false);
const handleObserveElement = useCallback(() => {
// 뷰포트 크기 구하기
let winH = window.innerHeight;
let winW = window.innerWidth;
// 관찰할 엘리먼트 위치 정보
let info1 = document.getElementById('box' + type)?.getBoundingClientRect();
// Y축 위치 확인 (임시로 200px 여유를 둠)
if (Number(info1?.y) < winH - 200 && Number(info1?.x) < winW) {
setIsViewing(true);
}
}, [type]);
여기서 200px을 빼준 이유는, 엘리먼트가 화면에 보이기 시작할 때 눈으로 확인하기 쉽게 하기 위해서다.
3. 화면에 보여질 때 스타일 변경하기
isViewing
상태가 true
일 때, 엘리먼트 배경색을 변경해서 사용자에게 시각적으로 표시한다.
return (
<Box id={'box' + type} isView={isViewing}>
{type}
</Box>
);
const Box = styled.div<IBox>`
background: pink;
width: 200px;
aspect-ratio: 1 / 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
${({ isView }) =>
isView &&
css`
background-color: green;
transition: 0.5s all ease-in;
`}
`;
---
| 실행화면
| 사진 적용
728x90
반응형
'REACT' 카테고리의 다른 글
Zustand란? (0) | 2024.02.05 |
---|---|
Redux Toolkit - RTK Query 사용 후기 및 정리 (0) | 2022.09.23 |
JSX에서 줄바꿈이 안되는 이유와 해결법 (0) | 2022.08.04 |
이미지 비교 슬라이더 구현 (Before / After) (0) | 2022.08.02 |
google-maps-react [리액트 구글 맵 기본 장소 마커 지우기] (0) | 2022.04.08 |