Skip to content

Instantly share code, notes, and snippets.

@robsonkades
Last active August 4, 2022 07:54
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robsonkades/0f256ab05944699b831031c7e6a8aa84 to your computer and use it in GitHub Desktop.
Save robsonkades/0f256ab05944699b831031c7e6a8aa84 to your computer and use it in GitHub Desktop.
import firebase from 'firebase';
import produce from 'immer';
import { useEffect, useReducer, useRef, useCallback } from 'react';
type IAction<K, V = void> = V extends void ? { type: K } : { type: K } & V;
export type IActionType =
| IAction<'LOAD_REQUEST'>
| IAction<
'LOAD_SUCCESS',
{
payload: {
value: firebase.firestore.QueryDocumentSnapshot[];
};
}
>;
function reducer(state: IStateType, action: IActionType): IStateType {
return produce(state, (draft) => {
switch (action.type) {
case 'LOAD_REQUEST': {
draft.isLoading = true;
break;
}
case 'LOAD_SUCCESS': {
const lastDocument =
action.payload.value[action.payload.value.length - 1];
if (lastDocument) {
draft.lastDocument = lastDocument;
}
draft.items = action.payload.value.map((item) => item.data());
draft.isLoading = false;
break;
}
default:
}
});
}
interface IPaginationOptions {
limit?: number;
}
type IStateType = {
isLoading: boolean;
lastDocument: firebase.firestore.QueryDocumentSnapshot;
items: firebase.firestore.DocumentData[];
};
interface IResponse {
isLoading: boolean;
items: firebase.firestore.DocumentData[];
nextPage(): Promise<void>;
previousPage(): Promise<void>;
}
export function usePagination(
query: firebase.firestore.Query,
{ limit = 3 }: IPaginationOptions = {},
): IResponse {
const [state, dispatch] = useReducer(reducer, {
isLoading: true,
} as IStateType);
const queryRef = useRef<firebase.firestore.Query>(query);
useEffect(() => {
dispatch({ type: 'LOAD_REQUEST' });
async function loadData(): Promise<void> {
const response = await queryRef.current.limit(limit).get();
dispatch({
type: 'LOAD_SUCCESS',
payload: {
value: response.docs,
},
});
}
loadData();
}, [limit]);
const nextPage = useCallback(async () => {
dispatch({ type: 'LOAD_REQUEST' });
const response = await queryRef.current
.startAfter(state.lastDocument)
.limit(limit)
.get();
dispatch({
type: 'LOAD_SUCCESS',
payload: {
value: response.docs,
},
});
}, [state.lastDocument, limit]);
const previousPage = useCallback(async () => {
dispatch({ type: 'LOAD_REQUEST' });
const response = await queryRef.current
.endBefore(state.lastDocument)
.limitToLast(limit)
.get();
dispatch({
type: 'LOAD_SUCCESS',
payload: {
value: response.docs,
},
});
}, [state.lastDocument, limit]);
return {
items: state.items,
nextPage,
previousPage,
isLoading: state.isLoading,
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment