Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LAB-6] firestore의 Pagination 중 이전 페이지 #192

Closed
SSY1203 opened this issue Mar 22, 2023 · 1 comment
Closed

[LAB-6] firestore의 Pagination 중 이전 페이지 #192

SSY1203 opened this issue Mar 22, 2023 · 1 comment
Assignees
Labels
Firebase Firebase 이슈 프로젝트 Q/A 프로젝트 Q/A 이슈 React React 관련 이슈

Comments

@SSY1203
Copy link

SSY1203 commented Mar 22, 2023

질문 작성자

신선영

문제 상황

전에 알려주신 대로 nextPage를 불러오는 것 까진 했는데, prevPage로 갈려면 어떻게 할지 고민하다가 lastVisible을 바꿔주면 되지 않을까 했는데, lastVisible을 지정해주기가 어려워서ㅠ 페이지화로 불러온 데이터를 이차원 배열로 받아서 렌더링을 해주는 게 좋을까요? 아니면 firestore에서 제공해주는 메서드들로 할 수 있는 방법이 따로 있을까요?
image
image
위 사진은 queryPage를 실행하는 버튼 클릭 시, 작동하는 과정입니다. 다음으로는 넘어가지는데 이전이 안돼요ㅠ

프로젝트 저장소 URL

환경 정보

  • 운영체제 정보 (Windows)
  • Node.js 정보 (예: v16.14.0)
  • 라이브러리 정보 (예: React v18.0.2)
@SSY1203 SSY1203 added React React 관련 이슈 프로젝트 Q/A 프로젝트 Q/A 이슈 labels Mar 22, 2023
@yamoo9
Copy link
Owner

yamoo9 commented Mar 22, 2023

문제 해결

Firestore 데이터베이스를 사용해 페이지네이션 할 때 이전 데이터를 가져오려면 endBefore 또는 endAt API를 사용해야 합니다.

endBefore 함수를 사용해 끝점을 임의로 선택할 수 있습니다. (참고)

아래 작성된 데모 코드를 확인해보세요. 😊

PaginationDemo
function PaginationDemo() {
  const [isLoading, setIsLoading] = useState(true);
  const [list, setList] = useState([]);
  const [lastVisible, setLastVisible] = useState(null);
  const [pageTotalCount, setPageTotalCount] = useState(0);
  const [hasPrevPage, setHasPrevPage] = useState(false);
  const [hasNextPage, setHasNextPage] = useState(true);
  const ITEMS_PER_VIEW = 2;

  useLayoutEffect(() => {
    getPageTotalCount();
    queryPage('next', ITEMS_PER_VIEW);
  }, []);

  useLayoutEffect(() => {
    const { length } = list;
    setHasNextPage(length === pageTotalCount ? false : true);
    setHasPrevPage(list.length <= ITEMS_PER_VIEW ? false : true);
  }, [list.length, pageTotalCount]);

  const sneakerItemsRef = collection(db, 'categories/sneakers/items');

  const getPageTotalCount = async () => {
    const res = await getCountFromServer(
      query(sneakerItemsRef, orderBy('createAt'))
    );

    setPageTotalCount(res.data().count);
  };

  const queryPage = async (type = 'next', limitCount) => {
    let q;
    if (!lastVisible) {
      q = query(sneakerItemsRef, orderBy('createAt'), limit(limitCount));
    } else {
      let isNext = type === 'next';
      let updateCount = list.length - limitCount;
      q = query(
        sneakerItemsRef,
        orderBy('createAt'),
        isNext ? startAfter(lastVisible) : endBefore(lastVisible),
        limit(
          isNext
            ? limitCount
            : updateCount <= limitCount
            ? limitCount
            : updateCount
        )
      );
    }
    const docSnapshot = await getDocs(q);

    if (isLoading) {
      setIsLoading(false);
    }

    const docs = docSnapshot.docs;
    queryData(type, docs);
  };

  const queryData = (type = 'next', docs) => {
    const listItems = [];

    docs.forEach((doc) => {
      listItems.push({ id: doc.id, ...doc.data() });
    });

    const updateList = type === 'next' ? [...list, ...listItems] : listItems;
    setList(updateList);

    let nextDoc = docs[docs.length - 1];
    if (nextDoc) {
      setLastVisible(nextDoc);
    }
  };

  return (
    <div
      style={{
        display: 'flex',
        gap: 20,
        flexFlow: 'column',
        alignItems: 'flex-start',
        padding: 40,
      }}
    >
      <h2>Pagination Firestore</h2>
      {isLoading ? (
        <div>LOADING...</div>
      ) : (
        <>
          <p>
            {list.length} / {pageTotalCount}
          </p>
          <div style={{ display: 'flex', gap: 4 }}>
            <button
              type="button"
              disabled={!hasPrevPage}
              onClick={() => {
                queryPage('prev', ITEMS_PER_VIEW);
              }}
            >
              Prev
            </button>
            <button
              type="button"
              disabled={!hasNextPage}
              onClick={() => {
                queryPage('next', ITEMS_PER_VIEW);
              }}
            >
              Next
            </button>
          </div>
          <ul>
            {list.map((item) => (
              <li key={item.id}>{item.name}</li>
            ))}
          </ul>
        </>
      )}
    </div>
  );
}

아래는 작동되는 이전, 다음 탐색 페이지네이션 데모입니다.

result

가이드 파일

가이드 파일을 다운로드 받아 테스트해보세요. 😃

Pagination-prev-next-demo.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Firebase Firebase 이슈 프로젝트 Q/A 프로젝트 Q/A 이슈 React React 관련 이슈
Projects
None yet
Development

No branches or pull requests

2 participants