Skip to content

Commit cf4d436

Browse files
author
Hoang Pham
committed
fix: preserver page data while refetching
1 parent eedb573 commit cf4d436

2 files changed

Lines changed: 214 additions & 61 deletions

File tree

Sources/SwiftUIQuery/InfiniteQuery.swift

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -628,35 +628,67 @@ public final class InfiniteQuery<
628628
}
629629

630630
/// Initial fetch for the first page
631-
/// This resets the query data and fetches from the beginning
631+
/// This preserves existing data during refetch to avoid empty page (TanStack Query behavior)
632632
public func internalFetch() async throws -> InfiniteData<TData, TPageParam> {
633-
// Reset data but preserve status for refetch scenarios
634-
// Only use pending status if we've never successfully fetched data
635-
let resetState: QueryState<InfiniteData<TData, TPageParam>> = if state.dataUpdateCount > 0 {
636-
// This is a refetch - preserve success status to avoid isLoading becoming true
637-
QueryState(
638-
data: InfiniteData<TData, TPageParam>(),
639-
dataUpdateCount: state.dataUpdateCount,
640-
dataUpdatedAt: state.dataUpdatedAt,
641-
error: nil,
642-
errorUpdateCount: state.errorUpdateCount,
643-
errorUpdatedAt: state.errorUpdatedAt,
644-
fetchFailureCount: 0,
645-
fetchFailureReason: nil,
646-
fetchMeta: nil,
647-
isInvalidated: false,
648-
status: .success, // Preserve success status for refetch
649-
fetchStatus: .idle
650-
)
651-
} else {
652-
// First fetch - use initial state with pending status
653-
initialState
654-
}
633+
// Store current state to revert if fetch is cancelled
634+
revertState = state
635+
636+
// Cancel any existing fetch
637+
fetchTask?.cancel()
655638

656-
setState(resetState)
639+
// Update fetch status to indicate we're fetching
640+
// This preserves existing data while showing fetching state
641+
dispatch(.fetch(meta: nil))
657642

658643
let initialParam = options.initialPageParam
659-
return try await fetchPage(param: initialParam, direction: .forward)
644+
645+
// Create new fetch task
646+
let task = Task<InfiniteData<TData, TPageParam>, Error> { @MainActor in
647+
do {
648+
// Execute the query function with initial page parameter
649+
let pageData = try await options.queryFn(queryKey, initialParam)
650+
651+
// Check if task was cancelled
652+
if Task.isCancelled {
653+
throw QueryError.cancelled
654+
}
655+
656+
// Create new infinite data with the first page
657+
let newData = InfiniteData(pages: [pageData], pageParams: [initialParam])
658+
659+
// Update state with the new data (replacing old data)
660+
dispatch(.success(data: newData, dataUpdatedAt: nil, manual: false))
661+
662+
// Clear the fetch task and direction
663+
self.fetchTask = nil
664+
self.currentFetchDirection = nil
665+
666+
return newData
667+
} catch {
668+
// Handle error cases
669+
if Task.isCancelled {
670+
throw QueryError.cancelled
671+
}
672+
673+
let typedError: QueryError = if let queryError = error as? QueryError {
674+
queryError
675+
} else {
676+
classifyError(error)
677+
}
678+
679+
dispatch(.error(error: typedError))
680+
681+
self.fetchTask = nil
682+
self.currentFetchDirection = nil
683+
throw typedError
684+
}
685+
}
686+
687+
// Store the task
688+
fetchTask = task
689+
690+
// Wait for the task to complete
691+
return try await task.value
660692
}
661693

662694
// MARK: - Observer Management

0 commit comments

Comments
 (0)