Last active
August 4, 2022 07:54
-
-
Save robsonkades/0f256ab05944699b831031c7e6a8aa84 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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