Skip to content

Commit 6f2ae92

Browse files
fix: refetching on infinite query when a page was deleted (TanStack#1124)
* test: add more test * feat: update infinite fetch * refactoring * refactoring * refactoring
1 parent b4aa576 commit 6f2ae92

File tree

2 files changed

+139
-2
lines changed

2 files changed

+139
-2
lines changed

src/core/query.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,10 @@ export class Query<TResult, TError> {
468468
cursor = config.getFetchMore(lastPage, pages)
469469
}
470470

471+
if (!Boolean(cursor) && typeof lastPage !== 'undefined') {
472+
return pages
473+
}
474+
471475
const page = await config.queryFn(...params, cursor)
472476

473477
return prepend ? [page, ...pages] : [...pages, page]

src/react/tests/useInfiniteQuery.test.tsx

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ const initialItems = (page: number): Result => {
2020
}
2121
}
2222

23-
const fetchItems = async (page: number, ts: number): Promise<Result> => {
23+
const fetchItems = async (page: number, ts: number, nextId?: any): Promise<Result> => {
2424
await sleep(10)
2525
return {
2626
items: [...new Array(10)].fill(null).map((_, d) => page * pageSize + d),
27-
nextId: page + 1,
27+
nextId: nextId ?? page + 1,
2828
ts,
2929
}
3030
}
@@ -1063,4 +1063,137 @@ describe('useInfiniteQuery', () => {
10631063
// ensure that Item: 4 is no longer rendered
10641064
expect(rendered.queryAllByText('Item: 4')).toHaveLength(0)
10651065
})
1066+
1067+
it('should compute canFetchMore correctly for falsy getFetchMore return value on refetching', async () => {
1068+
const key = queryKey()
1069+
const MAX = 2
1070+
1071+
function Page() {
1072+
const fetchCountRef = React.useRef(0)
1073+
const [isRemovedLastPage, setIsRemovedLastPage] = React.useState<boolean>(
1074+
false
1075+
)
1076+
const {
1077+
status,
1078+
data,
1079+
error,
1080+
isFetching,
1081+
isFetchingMore,
1082+
fetchMore,
1083+
canFetchMore,
1084+
refetch,
1085+
} = useInfiniteQuery<Result, Error, [string, number]>(
1086+
key,
1087+
(_key, nextId = 0) =>
1088+
fetchItems(
1089+
nextId,
1090+
fetchCountRef.current++,
1091+
nextId === MAX || (nextId === MAX - 1 && isRemovedLastPage)
1092+
? false
1093+
: undefined
1094+
),
1095+
{
1096+
getFetchMore: (lastGroup, _allGroups) => lastGroup.nextId,
1097+
}
1098+
)
1099+
1100+
return (
1101+
<div>
1102+
<h1>Pagination</h1>
1103+
{status === 'loading' ? (
1104+
'Loading...'
1105+
) : status === 'error' ? (
1106+
<span>Error: {error?.message}</span>
1107+
) : (
1108+
<>
1109+
<div>Data:</div>
1110+
{data?.map((page, i) => (
1111+
<div key={i}>
1112+
<div>
1113+
Page {i}: {page.ts}
1114+
</div>
1115+
<div key={i}>
1116+
{page.items.map(item => (
1117+
<p key={item}>Item: {item}</p>
1118+
))}
1119+
</div>
1120+
</div>
1121+
))}
1122+
<div>
1123+
<button
1124+
onClick={() => fetchMore()}
1125+
disabled={!canFetchMore || Boolean(isFetchingMore)}
1126+
>
1127+
{isFetchingMore
1128+
? 'Loading more...'
1129+
: canFetchMore
1130+
? 'Load More'
1131+
: 'Nothing more to load'}
1132+
</button>
1133+
<button onClick={() => refetch()}>Refetch</button>
1134+
<button onClick={() => setIsRemovedLastPage(true)}>
1135+
Remove Last Page
1136+
</button>
1137+
</div>
1138+
<div>
1139+
{isFetching && !isFetchingMore
1140+
? 'Background Updating...'
1141+
: null}
1142+
</div>
1143+
</>
1144+
)}
1145+
</div>
1146+
)
1147+
}
1148+
1149+
const rendered = render(<Page />)
1150+
1151+
rendered.getByText('Loading...')
1152+
1153+
await waitFor(() => {
1154+
rendered.getByText('Item: 9')
1155+
rendered.getByText('Page 0: 0')
1156+
})
1157+
1158+
fireEvent.click(rendered.getByText('Load More'))
1159+
1160+
await waitFor(() => rendered.getByText('Loading more...'))
1161+
1162+
await waitFor(() => {
1163+
rendered.getByText('Item: 19')
1164+
rendered.getByText('Page 0: 0')
1165+
rendered.getByText('Page 1: 1')
1166+
})
1167+
1168+
fireEvent.click(rendered.getByText('Load More'))
1169+
1170+
await waitFor(() => rendered.getByText('Loading more...'))
1171+
1172+
await waitFor(() => {
1173+
rendered.getByText('Item: 29')
1174+
rendered.getByText('Page 0: 0')
1175+
rendered.getByText('Page 1: 1')
1176+
rendered.getByText('Page 2: 2')
1177+
})
1178+
1179+
rendered.getByText('Nothing more to load')
1180+
1181+
fireEvent.click(rendered.getByText('Remove Last Page'))
1182+
1183+
await waitForMs(10)
1184+
1185+
fireEvent.click(rendered.getByText('Refetch'))
1186+
1187+
await waitFor(() => rendered.getByText('Background Updating...'))
1188+
1189+
await waitFor(() => {
1190+
rendered.getByText('Page 0: 3')
1191+
rendered.getByText('Page 1: 4')
1192+
})
1193+
1194+
expect(rendered.queryByText('Item: 29')).toBeNull()
1195+
expect(rendered.queryByText('Page 2: 5')).toBeNull()
1196+
1197+
rendered.getByText('Nothing more to load')
1198+
})
10661199
})

0 commit comments

Comments
 (0)