fix: prevent infinite rerendering of DataTable (#18087)

This commit is contained in:
Eunjae Lee
2024-12-11 14:03:17 +00:00
committed by GitHub
parent 6739ed3a87
commit 7d2523e823
4 changed files with 39 additions and 37 deletions
@@ -2,23 +2,27 @@
import { useCallback, useEffect } from "react";
export const useFetchMoreOnBottomReached = (
tableContainerRef: React.RefObject<HTMLDivElement>,
fetchNextPage: () => void,
isFetching: boolean,
totalFetched: number,
totalDBRowCount: number
) => {
export const useFetchMoreOnBottomReached = ({
tableContainerRef,
hasNextPage,
fetchNextPage,
isFetching,
}: {
tableContainerRef: React.RefObject<HTMLDivElement>;
hasNextPage: boolean;
fetchNextPage: () => void;
isFetching: boolean;
}) => {
const fetchMoreOnBottomReached = useCallback(
(containerRefElement?: HTMLDivElement | null) => {
if (containerRefElement) {
const { scrollHeight, scrollTop, clientHeight } = containerRefElement;
if (scrollHeight - scrollTop - clientHeight < 300 && !isFetching && totalFetched < totalDBRowCount) {
if (scrollHeight - scrollTop - clientHeight < 300 && !isFetching && hasNextPage) {
fetchNextPage();
}
}
},
[fetchNextPage, isFetching, totalFetched, totalDBRowCount]
[fetchNextPage, isFetching]
);
useEffect(() => {
@@ -162,21 +162,22 @@ export default function MemberList(props: Props) {
const [state, dispatch] = useReducer(reducer, initialState);
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
const { data, isPending, fetchNextPage, isFetching } = trpc.viewer.teams.listMembers.useInfiniteQuery(
{
limit: 10,
searchTerm: debouncedSearchTerm,
teamId: props.team.id,
},
{
enabled: !!props.team.id,
getNextPageParam: (lastPage) => lastPage.nextCursor,
placeholderData: keepPreviousData,
refetchOnWindowFocus: true,
refetchOnMount: true,
staleTime: 0,
}
);
const { data, isPending, hasNextPage, fetchNextPage, isFetching } =
trpc.viewer.teams.listMembers.useInfiniteQuery(
{
limit: 10,
searchTerm: debouncedSearchTerm,
teamId: props.team.id,
},
{
enabled: !!props.team.id,
getNextPageParam: (lastPage) => lastPage.nextCursor,
placeholderData: keepPreviousData,
refetchOnWindowFocus: true,
refetchOnMount: true,
staleTime: 0,
}
);
// TODO (SEAN): Make Column filters a trpc query param so we can fetch serverside even if the data is not loaded
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
@@ -633,13 +634,12 @@ export default function MemberList(props: Props) {
getRowId: (row) => `${row.id}`,
});
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached(
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached({
tableContainerRef,
hasNextPage,
fetchNextPage,
isFetching,
totalFetched,
totalDBRowCount
);
});
const numberOfSelectedRows = table.getSelectedRowModel().rows.length;
@@ -422,13 +422,12 @@ export function RoutingFormResponsesTable({
},
});
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached(
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached({
tableContainerRef,
hasNextPage,
fetchNextPage,
isFetching,
totalFetched,
totalDBRowCount
);
});
if (isHeadersLoading || ((isFetching || isLoading) && !data)) {
return <DataTableSkeleton columns={4} columnWidths={[200, 200, 250, 250]} />;
@@ -117,7 +117,7 @@ export function UserListTable() {
const columnFilters = useColumnFilters();
const { data, isPending, fetchNextPage, isFetching } =
const { data, isPending, hasNextPage, fetchNextPage, isFetching } =
trpc.viewer.organizations.listMembers.useInfiniteQuery(
{
limit: 30,
@@ -428,13 +428,12 @@ export function UserListTable() {
},
});
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached(
const fetchMoreOnBottomReached = useFetchMoreOnBottomReached({
tableContainerRef,
hasNextPage,
fetchNextPage,
isFetching,
totalFetched,
totalDBRowCount
);
});
const numberOfSelectedRows = table.getSelectedRowModel().rows.length;