React + firebase 무한스크롤 만들기(react-bottom-scroll-listener)

리뮤츠·2022년 10월 18일
1
  • firebase v9 기준으로 작성됨
  • react-bottom-scroll-listener를 사용해서 스크롤이 바닥에 닿았을때 다음 글을 파이어베이스에서 가져오는 작업

firebase에서 문서 가져오기

firebase에서 문서를 가져오는 방법은 다음과 같다.

const Home = () => {
	const [doc, setDoc] = useState([]);
	let q = query(
		collection(dbService, "문서이름"), //여기서 dbService는 getFirestore()입니다.
		orderBy("createdAt", "desc") //생성날짜 내림차순(최신순)으로 가져오기
	);
	onSnapshot(q, (snapshot) => {
		const arr = snapshot.docs.map((doc) => ({...doc.data()}));
		setDoc(arr);
	});
}

우리는 여기에 무한스크롤을 추가해야한다.

react-bottom-scroll-listener 설치

npm install react-bottom-scroll-listener

yarn add react-bottom-scroll-listener

자세한 사용방법은 [npm문서]를 참조.
스크롤 위치나 기타등등 조절할 수 있는듯 하다.

문서 가져오기

기본틀

우선 컴포넌트 함수 바깥에 변수 하나를 선언해준다.

let lastVisible = undefined;

const Home = () => {}

쿼리설정

lastVisible은 남은 게시글이 있는지 여부를 판단하는 boolean값이 될거다.
모든 게시글을 불러왔을 때 -1로 선언할 예정이다.

let q;  //경우에 따라 다르게 선언해야되므로 일단 undefinded 선언
    if (lastVisible === -1) {
        return //남은 게시글이 없으면 더이상 실행 안함
    } else if (lastVisible) {
        q = query(collection(dbService, "문서이름"),orderBy("createdAt", "desc"),limit(2),startAfter(lastVisible));
        //limit로 몇개를 불러올건지 결정함
        //남은 게시글이 있으면 startAfter로 방금전에 불러온 게시글의 다음 글부터 불러옴
    } else {
        q = query(collection(dbService, "문서이름"),orderBy("createdAt", "desc"),limit(5));
        //최초 페이지 렌더링
    }

가져온 문서 뿌리기

그리고 데이터를 뿌릴 때 lastVisible을 핸들링 해준다.
Array 병합시 꼭 새로 불러온 문서는 뒤에 넣어줘야한다.
안그러면 스크롤을 내리고 있는데 새 글이 맨위에 렌더링되는 참사가....
Array.push 또는 아래와 같이 작성해준다.

onSnapshot(q, (snapshot) => {
	const docArr = snapshot.docs.map((doc) => ({...doc.data()}));
	const arr = [...doc, ...docArr]; //불러온 데이터와 기존의 데이터를 하나의 Array로 만들자
    setDoc(arr);
    if(snapshot.docs.length === 0) { //남은 게시글이 없으면
    	lastVisible = -1;
    } else {
	    lastVisible = snapshot.docs[snapshot.docs.length - 1] //index번호로 받아야 하니 length에서 -1을 해준다
    }
});

react-bottom-scroll-listener

그리고 최초에 설치한 react-bottom-scroll-listener를 사용해서 스크롤바가 바닥에 닿으면 문서를 불러오는 함수를 실행시켜주자!
hooks의 이름은 다음과 같다.

useBottomScrollListener(콜백함수);

컴포넌트를 넘나들때(22/12/01 추가)

분명 잘 돌아갔던거 같은데
갑자기 선언한 lastVisible이 초기화되지 않는 오류가 발생했다.
컴포넌트를 렌더링 했을 때 lastVisible을 다시 undefined로 선언해주자.

useEffect(() => {
	lastVisible = undefined;
},[])

코드 전문

const Home = () => {
	const [doc, setDoc] = useState([]);
    const getNextPage = () => {
    	let q;
    	if (lastVisible === -1) {
    	    return;
    	} else if (lastVisible) {
        	q = query(collection(dbService, "문서이름"),orderBy("createdAt", "desc"),limit(2),startAfter(lastVisible));
    	} else {
        	q = query(collection(dbService, "문서이름"),orderBy("createdAt", "desc"),limit(5));
    	}
        
        onSnapshot(q, (snapshot) => {
			const docArr = snapshot.docs.map((doc) => ({...doc.data()}));
			const arr = [...doc, ...docArr];
    		setDoc(arr);
    		if(snapshot.docs.length === 0) {
    			lastVisible = -1;
    		} else {
	    		lastVisible = snapshot.docs[snapshot.docs.length - 1]
    		}
		});
    }
    
    useBottomScrollListener(getNextPost); //스크롤이 바닥에 닿을때마다 문서 불러오기
    
    useEffect(() => {
    	lastVisible = undefined; //lastVisible 초기화
        getNextPost(); //최초 페이지 렌더링
    },[]);
}
profile
역시 퍼블이 재밋당께

1개의 댓글

comment-user-thumbnail
2023년 4월 26일

감사합니당

답글 달기