Skip to content

Commit bc03037

Browse files
author
Hoang Pham
committed
feat: dedup request
1 parent 16e66aa commit bc03037

2 files changed

Lines changed: 437 additions & 8 deletions

File tree

Sources/SwiftUIQuery/Query.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ public final class Query<TData: Sendable, TKey: QueryKey>: AnyQuery {
425425
}
426426

427427
/// Cancel any ongoing fetch operation
428+
/// Note: This should only be called when explicitly requested or when no observers remain
428429
public func cancel() {
429430
fetchTask?.cancel()
430431
fetchTask = nil
@@ -463,15 +464,15 @@ public final class Query<TData: Sendable, TKey: QueryKey>: AnyQuery {
463464
observers.removeAll { $0.id == observer.id }
464465

465466
if observers.isEmpty {
466-
// Cancel ongoing fetch if no observers and allow revert
467-
if let revertState {
467+
// If there's a revert state and we're currently fetching, revert to previous state
468+
if let revertState, state.fetchStatus == .fetching {
468469
setState(revertState)
469470
self.revertState = nil
470471
}
471472

472-
// If the query is still fetching, let it continue to cache the result
473-
// Only cancel if we can safely revert
474-
if fetchTask != nil, revertState != nil {
473+
// Cancel any ongoing fetch when no observers remain
474+
// This prevents unnecessary network usage when no one is listening for the result
475+
if fetchTask != nil {
475476
fetchTask?.cancel()
476477
fetchTask = nil
477478
}
@@ -527,13 +528,19 @@ public final class Query<TData: Sendable, TKey: QueryKey>: AnyQuery {
527528
// MARK: - Fetch Implementation
528529

529530
/// Internal fetch implementation that executes the query function
531+
/// Implements request deduplication - if a fetch is already in progress,
532+
/// returns the existing promise instead of starting a new one
530533
public func internalFetch() async throws -> TData {
534+
// If we're already fetching, return the existing promise
535+
// This implements request deduplication similar to TanStack Query
536+
if let existingTask = fetchTask, state.fetchStatus == .fetching {
537+
// Return the existing task's value - all callers share the same request
538+
return try await existingTask.value
539+
}
540+
531541
// Store current state to revert if fetch is cancelled
532542
revertState = state
533543

534-
// Cancel any existing fetch
535-
fetchTask?.cancel()
536-
537544
// Update state to fetching
538545
dispatch(.fetch(meta: nil))
539546

0 commit comments

Comments
 (0)