T
TanStack3y ago
blank-aquamarine

Is there a way to scroll to the top of the list?

I use useVirtualizer along with useInfiniteQuery. I display a list of items, and I let the user filter records. when a user selects filter criteria, I utilize the useInfiniteQuery to pass these filters to the back end, and receive the filtered data from the back end. the problem is, if initially there is lets say 100 items in the list, and post- filter request there is 50, the scroller location is at the bottom of the list, which resulting in the virtualList spamming requests to the back end asking for me (if there's more, of course). I tried using scrollToIndex(0), or scrollToIndex(items[0]), and I tried a few other potential answers I scraped from GitHub like using rangeExtractor, but none of them seem to work.
3 Replies
rival-black
rival-black3y ago
I think you can just scroll the div, like not use react-virtual's APIs, but just the native ones. Plus IIRC useVirtualizer already needs a ref on the scrollable parent, so you already have access to the DOM node. https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTo
Element: scrollTo() method - Web APIs | MDN
The scrollTo() method of the Element interface scrolls to a particular set of coordinates inside a given element.
blank-aquamarine
blank-aquamarineOP3y ago
@bostonsheraff Thanks for your response. I added a useEffect that listens to the filters state and when there's a change it scrolls to the top of the current ref. it does indeed scroll to the top, but the problem is that it still fetches multiple pages as if the scroller location is at the bottom of the component. I created a custom hook,
import { useEffect } from 'react';
import { LogFilters } from 'types/models/Assignment';

interface ParentRef {
current: HTMLElement | null;
}

export const useScrollToIndex = (
filters: LogFilters,
parentRef: ParentRef,
refetch: () => void
) => {
useEffect(() => {
if (filters && parentRef.current) {
parentRef.current.scrollTop = 0;
refetch();
}
}, [filters]);
};
import { useEffect } from 'react';
import { LogFilters } from 'types/models/Assignment';

interface ParentRef {
current: HTMLElement | null;
}

export const useScrollToIndex = (
filters: LogFilters,
parentRef: ParentRef,
refetch: () => void
) => {
useEffect(() => {
if (filters && parentRef.current) {
parentRef.current.scrollTop = 0;
refetch();
}
}, [filters]);
};
and in the main component I use the hook like that:
useScrollToIndex(filters, parentRef, refetch)
useScrollToIndex(filters, parentRef, refetch)
filters comes from the useState,
const [filters, setFilters] = useState<{
selectedStudents: string[];
selectedTeams: string[];
selectedActivityTypes: string[];
}>({
selectedStudents: [],
selectedTeams: [],
selectedActivityTypes: [
'engineeringNotebookSteps',
'kudos',
'feelingsTracker',
],
});
const [filters, setFilters] = useState<{
selectedStudents: string[];
selectedTeams: string[];
selectedActivityTypes: string[];
}>({
selectedStudents: [],
selectedTeams: [],
selectedActivityTypes: [
'engineeringNotebookSteps',
'kudos',
'feelingsTracker',
],
});
parentRef comes from the useVirtualize
const parentRef = React.useRef<HTMLDivElement>(null);

const rowVirtualizer = useVirtualizer({
count: hasNextPage ? mergedLogs.length + 1 : mergedLogs.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 100,
overscan: 2,
});
const parentRef = React.useRef<HTMLDivElement>(null);

const rowVirtualizer = useVirtualizer({
count: hasNextPage ? mergedLogs.length + 1 : mergedLogs.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 100,
overscan: 2,
});
, and refetch
const {
data: logData,
isLoading: isLoadingLogs,
isFetching: IsFetchingLogs,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
isRefetching: isRefetchingLogs,
refetch,
} = useInfiniteLogs({
assignmentId,
assignmentSetId,
filters,
});
const {
data: logData,
isLoading: isLoadingLogs,
isFetching: IsFetchingLogs,
isFetchingNextPage,
fetchNextPage,
hasNextPage,
isRefetching: isRefetchingLogs,
refetch,
} = useInfiniteLogs({
assignmentId,
assignmentSetId,
filters,
});
comes from useInfiniteQuery
blank-aquamarine
blank-aquamarineOP3y ago
Heres a mini video that might help visualize the problem i'm facing: as soon as I select some filters, and hit 'see results', the scroller goes to the top, but it still fetches multiple pages as if the scroll is still in the bottom of the list

Did you find this page helpful?