Pagination firestore using react-redux-firebase library

Viewed 1327

I want to build a pagination feature using the library react-redux-firebase: https://react-redux-firebase.com/

Furthermore, I want to build a dynamic orderby dropdown. So, when I change the orderby option, the startAt parameter takes the current orderby field and compares it(because startAt is related to the previous orderby). My problem is when in the current page stays all the registers with the same value because the startAt gets a value that it can't track in the database.

Can anyone suggests an optimal method to build pagination with a dynamic orderby option using react-redux-firebase library?.

1 Answers

Try something like this

import { useState, useEffect } from "react";
import { useFirestore, useFirestoreConnect } from "react-redux-firebase";
import { useSelector } from "react-redux";
import { APPOINTMENTS_COLLECTION } from "constants/firebasePaths";
import { RootState } from "store/rootReducer";
import { Appointment } from "model";
import { first, last  } from 'lodash';

export function useAppointmentsList() {
  const [pointer, setPointer] = useState<string | undefined>(undefined) // Current pointer
  const [forwardPointer, setForwardPointer] = useState<string | undefined>(undefined) // Forward pointer
  const [backwardPointers, setBackwardPointers] = useState<string[]>([]) // Backward pointers chain
  const [page, setPage] = useState(0) // current  page
  const [limit, setLimit] = useState(5) // limit

  const firestore = useFirestore();
  // Get auth from redux state
  const auth = useSelector(({ firebase: { auth } }: RootState) => auth);

  useFirestoreConnect([
    {
      collection: APPOINTMENTS_COLLECTION,
      where: ["createdBy", "==", auth.uid],
      orderBy: ["createdAt", "desc"],
      limit: limit + 1,
      startAt: pointer
    },
  ]);
  
  // Get appointments from redux state
  var appointments = useSelector(
    ({ firestore: { ordered } }: RootState) => ordered.appointments
  ) as Appointment[];

  // Set forward pointer
  useEffect(() => {
    if (appointments && appointments.length > limit) { 
      setForwardPointer(last(appointments)?.createdAt)
      appointments.splice(-1,1)
    }
  }, [appointments])

  // add pointer to back chain 
  useEffect(() => {
    if (appointments) {
      const firstItem = first(appointments)
      if (firstItem) { 
        setBackwardPointers((prevState) => { 
          const newState = prevState
          newState[page] = firstItem.createdAt
          return newState
        })
      }
    }
  }, [page, appointments])
  
  const handlePageChange = (event: any, newPage: number) => {
    if (appointments) {
      if (page < newPage && forwardPointer) {
        // Forward
        setPointer(forwardPointer)
      } else if (page > newPage) {
        // Backward
        setPointer(backwardPointers[newPage])
      }
    }
    if (appointments && appointments.length === limit) {
      setPage(newPage);
    } else { 
      console.log("No more record")
    }
  };

  return { appointments, limit, setLimit, page, handlePageChange};
}

and then use in component:

import React from "react";
import { useAppointmentsList } from "./useAppointmentsList";
import { Appointment } from "model";

type AppointmentsListProps = {
  className: string;
};

const AppointmentsList: React.FC<AppointmentsListProps> = () => {
  const {
    appointments,
    limit,
    setLimit,
    page,
    handlePageChange
  } = useAppointmentsList();
  
const handleLimitChange = (event: any) => {
    setLimit(event.target.value);
  };
  return (
    <div>
     ...
              <TablePagination
                component="div"
                count={-1}
                onChangePage={handlePageChange}
                onChangeRowsPerPage={handleLimitChange}
                page={page}
                rowsPerPage={limit}
                rowsPerPageOptions={[5, 10, 25]}
              />
            </Card>
    </div>
  );
};
export default AppointmentsList;

Related