Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- 그리디알고리즘
- 코테
- 완전탐색
- 파이썬
- JS
- DFS활용
- 구현
- 스택자료구조
- CSS
- DFS
- 코드트리
- 백준
- 코딩테스트실력진단
- 백준알고리즘
- DP
- 그리디
- socket.io
- django
- 알고리즘
- react-query
- 스택
- 블챌
- Express
- 자료구조
- 문자열
- 재귀
- BFS
- DFS기초
- react
- 코딩테스트
Archives
- Today
- Total
꾸준하게 거북이처럼
Intersection Observer API 로 무한 스크롤 구현해보기 (with React) 본문
문제 상황
무한 스크롤을 구현했는데 문제가 있었다.
처음 렌더링이 되자마자 page가 setState에 의해 +1 증가가 되어서, 뒷 페이지가 먼저 렌더링 되었다.
여러 블로그글을 찾아본 결과, isLoading라는 상태값을 추가해서 페이지가 로딩 중이면 page+1 가 되지 않도록! 코드를 아래처럼 수정했다.
import React, { useState, useEffect, useRef, useCallback } from "react";
const MainPage = () => {
//...
const [postList, setPostList] = useState([]);
const [page, setPage] = useState(1);
//..
const [isLoading, setIsLoading] = useState(true);// 1️⃣ 처음 부터 로딩 시작
const obsRef = useRef(null); //observer Element
const endRef = useRef(false); //모든 글 로드 확인
useEffect(() => {// page가 바뀌거나, 정렬 기준이 바뀐다면 post 가져오기.
getPostLoadMore();
}, [page, sort]);
useEffect(() => {
const observer = new IntersectionObserver(obsHandler, { threshold: 1 }); // obsRef가 100% 가 보이면 로드하기.
if (obsRef.current) observer.observe(obsRef.current);
return () => {
observer.disconnect();
};
}, [isLoading]);// isLoading 상태 값이 바뀌면서, observer는 다시 관찰(obsHandler함수 호출)
const obsHandler = (entries) => {
const target = entries[0];
if (!endRef.current && target.isIntersecting && !isLoading) {//4️⃣ 현재 페이지 로딩 중이라면, page 값을 증가하지 않는다.
setPage((prev) => prev + 1); //페이지 값 증가
}
};
const getPostLoadMore = useCallback(async () => {
setIsLoading(true);//2️⃣ 현재 페이지를 로딩하고 있음에 true
let body = {
sort,
searchTerm,
page,
};
try {
const { data } = await axios.post("/api/post/list", body);
if (data.success) {
if (page === 1) {
setPostList([...data.postList]);
} else setPostList((prev) => [...prev, ...data.postList]);
setIsLoading(false);// 3️⃣ 현재 페이지 로딩이 끝났음에 false
if (data.postList.length < 8) {
endRef.current = true;
}
}
} catch (e) {
console.log(e);
}
}, [page, sort, searchTerm]);
return (
<div className={style.mainWrapper}>
//...
<div className={style.observer} ref={obsRef}></div>
</div>
);
};
export default MainPage;
=> 첫 페이지가 먼저 요청이 되긴하지만, 바로 page가 +1 되버리면서 page2도 요청 되버리는 것 같았다.
그래서 현재 페이지가 로딩 중이라면, true를 isLoading 상태값에 할당하고, 로딩이 끝나면 false를 isLoading 상태값에 할당한다.
그러면 스크롤을 내리면서 observer가 obsRef를 발견을 해도!! 현재 페이지가 아직 로딩 중이라면, page 상태값을 증가 시키지 않을 것이다.
** 주의할 것은 맨 처음에 로딩할 때, 아직 데이터가 없기 때문에(가져오는 중) 제일 하단에 있는 obsRef가 위쪽으로 올라와서 observer가 해당 ref를 관찰 해버릴 수 있다는 점이다.
'개인공부 > React' 카테고리의 다른 글
refactor : useMuate의 mutateAsync 사용해서 비동기 함수로 이벤트 이후 부분 처리하기 (0) | 2023.06.27 |
---|---|
react-query: 자동으로 댓글 업데이트 시키기(useMutate, useQuery) (0) | 2023.06.27 |
React 외부 클릭시 모달 사라지게 하기 (0) | 2023.06.16 |
useState 와 useRef 의 차이점 (0) | 2023.06.07 |
Bearer token 방식으로 axios로 API 요청하기 (with create react app) (0) | 2023.05.23 |
Comments