I'm using React with @tanstack/react-table and react-query to implement a paginated table with server-side filtering and sorting. I'm encountering an issue where selecting a date filter sometimes causes the table to display an incorrect or empty page and also triggers redundant API calls when the datepicker is opened or closed.
I have a separate state of 'pageIndex' that is sent to the database for filter operations. When I select a date, I set the 'pageIndex' to 0, but as per my observation, it again sets the 'pageIndex' to the previous pageIndex, which causes a redundant API call.
The state and functions are:
const [pageIndex, setPageIndex] = useState<number>(0);
const [pageCount, setPageCount] = useState<number>(0);
const [pageSize, setPageSize] = useState<number>(5);
const [totalRows, setTotalRows] = useState<number>(0);
const [searchQuery, setSearchQuery] = useState<string>('');
const [sorting, setSorting] = useState<SortingState>([]);
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const fetchPackageDetails = async (params: object) => {
try {
let startDate, endDate;
if (selectedDate) {
const { start, end } = convertToUTCStartAndEnd(selectedDate);
startDate = start;
endDate = end;
}
const response = await getPaginatedPackageDetails({
...params,
startDate,
endDate,
});
if (response.status === 200 || response.status === 204) {
return response;
}
} catch (error) {
console.log('Error while fetching package details: ', error);
}
};
const handlePaginationChange = (pagination: {
pageSize: number;
pageIndex: number;
}) => {
console.log(
'Changing pageiNdex in handlePaginationChange: ',
pageIndex,
pagination.pageIndex,
);
setPageSize(pagination.pageSize);
setPageIndex(pagination.pageIndex);
};
const handleSortingChange = (newSorting: SortingState) => {
setSorting(newSorting);
};
const {
data: bookings,
isLoading,
isSuccess,
isError,
} = useQuery({
queryKey: [
'bookingList',
{ pageSize, pageIndex, searchQuery, sorting, selectedDate },
],
staleTime: 1000 * 60 * 2,
retry: 1,
retryDelay: 1000,
queryFn: async () => {
const params: FetchParams = {
pageSize,
pageIndex,
searchQuery,
sortField: sorting[0]?.id || '',
sortOrder: sorting[0]?.desc ? 'desc' : 'asc',
};
if (activeTab === 'package') {
return await fetchPackageDetails(params);
} else {
// return await fetchSessionDetails(params);
}
},
});
useEffect(() => {
if (isSuccess && !isLoading) {
if (activeTab === 'package') {
setPackageDetails(bookings?.data?.data);
} else if (activeTab === 'session') {
setSessionDetails(bookings?.data?.data);
}
// Only update these values, remove setPageIndex
setPageCount(bookings?.data?.pageCount);
setTotalRows(bookings?.data?.totalRows);
}
}, [isSuccess, bookings, isLoading, activeTab]);
Example usage:
<div className="flex md:justify-normal gap-3 justify-between items-center">
<div className="relative inline-block">
<DatePicker
selected={selectedDate}
onChange={handleDateChange}
placeholderText="Filter by: Date"
className="border text-[14px] border-[#D9D9D9] rounded-t-[15px] rounded-b-none px-4 py-1.5 rounded"
open={isDatePickerOpen}
onCalendarOpen={() => setIsDatePickerOpen(true)}
onCalendarClose={() => setIsDatePickerOpen(false)}
customInput={<CustomInput />}
popperClassName="left-0 right-0 md:!-left-[30px]"
/>
</div>
</div>
<div className="mt-4">
<ServerDataTable
data={getActiveTab()}
columns={packageDetailsCols}
noDataText="No packages found"
pageCount={pageCount}
pageIndex={pageIndex}
pageSize={pageSize}
onPaginationChange={handlePaginationChange}
isLoading={isLoading}
totalRows={totalRows}
onSortingChange={handleSortingChange}
/>
</div>
Redundant API calls:
First API call after I change the date, which returns the actual data which is required
Second unnecessary API call, in which 'pageIndex' is sent as '1' and I dont know 1
Also, I have noticed that when I open and close the date picker, the handlePaginationChange is getting triggered.

