Skip to content

Commit

Permalink
chore: chnaged folder structure and some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedx33 committed Oct 10, 2024
1 parent ed38d15 commit 4d63c58
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 76 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# duck-query

## 0.3.0

### Minor Changes

- added refetchOnWindowFocus - gcTime

## 0.1.9

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "duck-query",
"version": "0.2.9",
"version": "0.3.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"module": "dist/index.mjs",
Expand Down
144 changes: 144 additions & 0 deletions packages/duck-query/src/core/useQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { useEffect, useRef, useState } from "react";

type Query<T> = {
queryKey: string;
queryFn: () => Promise<T>;
staleTime?: number;
refetchInterval?: number;
refetchOnWindowFocus?: boolean;
gcTime?: number;
};

type CacheEntry<T> = {
data: T;
timestamp: number;
};

type QueryOptions<T> = {
data: T | null;
isLoading: boolean;
isError: boolean;
refetch: () => void;
};

// global cache cuz when i add it inside the hook it will rebuild everytime cuz the component destroys every hook when unmount
const cache: Record<string, CacheEntry<unknown>> = {};

export function useQueryNew<T>({
queryKey,
queryFn,
staleTime = 0,
refetchInterval = 0,
refetchOnWindowFocus = false,
gcTime,
}: Query<T>): QueryOptions<T> {
const [data, setData] = useState<T | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isError, setIsError] = useState<boolean>(false);
const key = JSON.stringify(queryKey);
const intervalRef = useRef<number | null>(null);
const staleCheckRef = useRef<number | null>(null);

const checkStale = () => {
const cachedData = cache[key];
if (cachedData && Date.now() - cachedData.timestamp > staleTime) {
fetcher();
}
};

const clearUnusedCache = (key: string, gcTime: number) => {
if (cache[key]) {
if (Date.now() - cache[key].timestamp > gcTime) {
delete cache[key];
}
}
};

const fetcher = async () => {
setIsLoading(true);
setIsError(false);
try {
const result = await queryFn();
setIsLoading(false);
cache[key] = {
data: result,
timestamp: Date.now(),
};
setData(result);
} catch (err) {
setIsError(true);
throw new Error(err as string);
} finally {
setIsLoading(false);
}
};

const refetch = () => {
fetcher();
};

useEffect(() => {
if (refetchOnWindowFocus) {
const handleVisibilityChange = () => {
const cachedData = cache[key];
const isStale = !cachedData || (Date.now() - cachedData.timestamp > staleTime);

if (document.visibilityState === "visible" && isStale) {
fetcher();
}
};

document.addEventListener("visibilitychange", handleVisibilityChange);

return () => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [key, staleTime, queryFn, refetchOnWindowFocus]);

useEffect(() => {
const cachedData = cache[key];
const isStale = cachedData && Date.now() - cachedData.timestamp > staleTime;

clearUnusedCache(key, gcTime as number);

if (staleTime > 0 && staleCheckRef.current === null) {
staleCheckRef.current = window.setInterval(() => {
checkStale();
}, staleTime);
}

if (refetchInterval !== 0 && intervalRef.current === null) {
intervalRef.current = window.setInterval(() => {
fetcher();
}, refetchInterval);
}

if (cachedData && !isStale) {
setData(cachedData.data as T);
return;
}

fetcher();

return () => {
if (intervalRef.current !== null) {
clearInterval(intervalRef.current);
}
if (staleCheckRef.current !== null) {
clearInterval(staleCheckRef.current);
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [key, staleTime, refetchInterval, gcTime]);



return {
data,
isLoading,
isError,
refetch,
};
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions packages/duck-query/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./core/useQuery"
74 changes: 0 additions & 74 deletions packages/duck-query/useQuery.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { useQueryNew } from "./duck-query/useQuery";
export * from "./duck-query/src"

0 comments on commit 4d63c58

Please sign in to comment.