Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: database query with subscribe never fetches #77

Open
wants to merge 2 commits into
base: dev-release
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 32 additions & 21 deletions packages/utils/src/useSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,21 @@ import {
type Unsubscribe = AuthUnsubscribe | FirestoreUnsubscribe | DatabaseUnsubscribe;

const firestoreUnsubscribes: Record<string, any> = {};
const queryCacheUnsubscribes: Record<string, () => void> = {};
const queryCacheSubscribes: Record<
string,
{ result: Promise<any>; unsubscribe: () => void }
> = {};
const eventCount: Record<string, number> = {};

interface CancellablePromise<T = void> extends Promise<T> {
cancel?: () => void;
}

type UseSubscriptionOptions<TData, TError, R> = UseQueryOptions<TData,
type UseSubscriptionOptions<TData, TError, R> = UseQueryOptions<
TData,
TError,
R> & {
R
> & {
onlyOnce?: boolean;
fetchFn?: () => Promise<TData | null>;
};
Expand All @@ -54,10 +59,10 @@ function firestoreUnsubscribe(subscriptionHash: string) {
}

function queryCacheUnsubscribe(subscriptionHash: string) {
const queryCacheUnsubscribe = queryCacheUnsubscribes[subscriptionHash];
const queryCacheUnsubscribe = queryCacheSubscribes[subscriptionHash];
if (queryCacheUnsubscribe) {
queryCacheUnsubscribe();
delete queryCacheUnsubscribes[subscriptionHash];
queryCacheUnsubscribe.unsubscribe();
delete queryCacheSubscribes[subscriptionHash];
}
}

Expand All @@ -79,17 +84,15 @@ export function useSubscription<TData, TError, R = TData>(
const subscriptionHash = hashFn(subscriptionKey);
const queryClient = useQueryClient();


let resolvePromise: (data: TData | null) => void = () => null;
let rejectPromise: (err: any) => void = () => null;

const result: CancellablePromise<TData | null> = new Promise<TData | null>(
let result: CancellablePromise<TData | null> = new Promise<TData | null>(
(resolve, reject) => {
resolvePromise = resolve;
rejectPromise = reject;
}
);

result.cancel = () => {
queryClient.invalidateQueries(queryKey);
};
Expand All @@ -109,10 +112,10 @@ export function useSubscription<TData, TError, R = TData>(
}
}
} else {
const subscribedToQueryCache = !!queryCacheUnsubscribes[subscriptionHash];
const subscribedToQueryCache = !!queryCacheSubscribes[subscriptionHash];
if (!subscribedToQueryCache) {
const queryCache = queryClient.getQueryCache();
queryCacheUnsubscribes[subscriptionHash] = queryCache.subscribe((event) => {
const unsubscribe = queryCache.subscribe((event) => {
if (!event || event.query.queryHash !== hashFn(queryKey)) {
return;
}
Expand All @@ -127,28 +130,36 @@ export function useSubscription<TData, TError, R = TData>(
if (observersCount === 0) {
firestoreUnsubscribe(subscriptionHash);
} else {
const isSubscribedToFirestore = !!firestoreUnsubscribes[subscriptionHash];
const isSubscribedToFirestore =
!!firestoreUnsubscribes[subscriptionHash];
if (isSubscribedToFirestore) {
const cachedData = queryClient.getQueryData<TData | null>(queryKey);
const cachedData = queryClient.getQueryData<TData | null>(
queryKey
);
const hasData = !!eventCount[subscriptionHash];

if (hasData) {
resolvePromise(cachedData ?? null);
}
} else {
firestoreUnsubscribes[subscriptionHash] = subscribeFn(async (data) => {
eventCount[subscriptionHash] ??= 0;
eventCount[subscriptionHash]++;
if (eventCount[subscriptionHash] === 1) {
resolvePromise(data || null);
} else {
queryClient.setQueryData(queryKey, data);
firestoreUnsubscribes[subscriptionHash] = subscribeFn(
async (data) => {
eventCount[subscriptionHash] ??= 0;
eventCount[subscriptionHash]++;
if (eventCount[subscriptionHash] === 1) {
resolvePromise(data || null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
resolvePromise(data || null);
resolvePromise(data ?? null);

Otherwise, if data === false you get back null and you never get the actual value of the data. 🤦🏼‍♂️

I spent hours trying to figure out why my DB value of false kept coming back null.

} else {
queryClient.setQueryData(queryKey, data);
}
}
});
);
}
}
}
});
queryCacheSubscribes[subscriptionHash] = { result, unsubscribe };
} else {
result = queryCacheSubscribes[subscriptionHash].result;
}
}

Expand Down