InterSection Observer?
=> 브라우저 Viewport와 설정한 요소의 교차점을 관찰하여 요소가 viewport에 포함되는지 구별하는 기능 제공
- 페이지 스크롤 시 이미지를 Lazy-Loading 할 때
- 무한 스크롤을 통해 새로운 컨텐츠를 불러올 때
- 광고의 수익을 계산하기 위해 광고의 가시성을 참고할 떄
- 사용자가 결과를 볼 것인지에 따라 애니메이션 동작 여부를 결정할 때
무한 스크롤
사용자가 특정한 영역 하단에 도달했을 때, API가 호출되며 콘텐츠가 계속 로드되는 방식
-> 모든 데이터를 불러와 뿌려주는 방식은 렌더링 시간이 많이 소요되니까 ㅜ 바닥에 닿으면 불러오자!구글에 정보가 정말 많아서 라이브러리 없이도 구현 해보면 좋을 것 같아,,하지만,, 나는 당장 시간이 좀 없기 때무네,, 라이브러리를 잘 써보려고 한다,,ㅎ
react-intersection-observer
관찰하는 객체(observer) 하나를 ref로 설정한 후 해당하는 객체가 화면에 보이면 특정 코드를 실행시킬 수 있다.
https://github.com/thebuilder/react-intersection-observer#readme
설치
npm install react-intersection-observer --save
Import
import { useInView } from 'react-intersection-observer';
사용하기
const [ref, inView] = useInView();
...
return (
// 관찰할 객체에 ref를 달아준다.
<div ref={ref}></div>
)
나는 scroll area의 하단에 "안녕"이라고 붙여 놓았다.
<div className={styles.scrollarea}>
{products?.map((product) => {
return (
<ProductItem
key={product.productId}
product={product}
clickProduct={clickProduct}
/>
);
})}
<div ref={ref}>안녕</div>
</div>
콘솔창에 출력해볼 수 있다.
console.log(inView, '무한 스크롤 요청 🎃')
스크롤 시에 ref가 노출되면 특정 함수 실행하기
// 무한 스크롤
// 지정한 타겟 div가 화면에 보일 때 마다 서버에 요청을 보냄
const productFetch = () => {
axios
.get(`https://localhost:8080/products/main?pageNo=${page}&pageSize=5`)
.then((res) => {
// 리스트 뒤로 붙여주기
setProducts([...products, ...(res.data)])
// 요청 성공 시에 페이지에 1 카운트 해주기
setPage((page) => page + 1)
})
.catch((err) => {console.log(err)});
};
- 서버단에 페이지 번호와 사이즈를 넘겨주기로 약속했다.
- 더이상 페이지가 없으면 요청을 하지 않도록 하는 방식도 생각해보면 좋을 것 같다,, 근데 이제 그게 지금은 아닌,,ㅎ
useEffect(() => {
// inView가 true 일때만 실행한다.
if (inView) {
console.log(inView, '무한 스크롤 요청 🎃')
// 실행할 함수
productFetch();
}
}, [inView]);
전체 코드
import React, { useEffect, useState } from "react";
import HomeBanner from "../components/Home/HomeBanner";
import BottomNav from "../components/Nav/BottomNav";
import TopNav from "../components/Nav/TopNav";
import z from "../assets/images/z.png";
import styles from "./styles/Home.module.css";
import { useNavigate } from "react-router-dom";
import ProductItem from "../components/Product/ProductItem";
import axios from "axios";
import { useInView } from 'react-intersection-observer';
export default function Home() {
const navigate = useNavigate();
const [products, setProducts] = useState([]);
const [page, setPage] = useState(0); // 현재 페이지 번호 (페이지네이션)
const [ref, inView] = useInView();
// 무한 스크롤
// 지정한 타겟 div가 화면에 보일 때 마다 서버에 요청을 보냄
const productFetch = () => {
axios
.get(`https://localhost:8080/products/main?pageNo=${page}&pageSize=5`)
.then((res) => {
console.log(res.data);
// 리스트 뒤로 붙여주기
setProducts([...products, ...(res.data)])
// 요청 성공 시에 페이지에 1 카운트 해주기
setPage((page) => page + 1)
})
.catch((err) => {console.log(err)});
};
useEffect(() => {
// inView가 true 일때만 실행한다.
if (inView) {
console.log(inView, '무한 스크롤 요청 🎃')
productFetch();
}
}, [inView]);
const clickProduct = (id) => {
navigate(`/detail/${id}`);
};
return (
<div className={styles.background}>
<TopNav />
<HomeBanner />
<div className={styles.body}>
<div className={styles.onsale}>판매중</div>
<div className={styles.scrollarea}>
{products?.map((product) => {
return (
<ProductItem
key={product.productId}
product={product}
clickProduct={clickProduct}
/>
);
})}
<div ref={ref}>안녕</div>
</div>
<BottomNav/>
</div>
</div>
);
}
실행 결과
"안녕" div가 하단 고정 네비에 가려져 보이지는 않지만, inView는 true로 잘 동작하는 것을 확인할 수 있다
'Project > zum:go' 카테고리의 다른 글
[React] axios로 다중 파일 전송 - 이미지, JSON (0) | 2023.02.07 |
---|---|
[React] 타이머 기능 구현하기 - setInterval (0) | 2023.02.05 |
[React] 실시간 채팅 구현하기 - STOMP (0) | 2023.02.03 |
[React] swiper로 이미지 슬라이드 구현하기 (0) | 2023.01.28 |
[React] 카카오 로그인 (0) | 2023.01.26 |
댓글