@qiaopeng/tanstack-query-plus 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -210,7 +210,7 @@ function Dashboard() {
210
210
 
211
211
  ## 8. 预取(Prefetch)
212
212
 
213
- 提供多种预取策略:悬停、路由变化、智能预取、视口内预取(可选依赖)。
213
+ 提供多种预取策略:悬停、路由变化、智能预取、视口内预取(可选依赖),并支持 `minInterval` 节流与 `stale` 检查。
214
214
 
215
215
  ```tsx
216
216
  import { useEffect } from 'react'
@@ -218,21 +218,21 @@ import { useHoverPrefetch, useRoutePrefetch, useSmartPrefetch } from '@qiaopeng/
218
218
  import { queryKeys } from '@qiaopeng/tanstack-query-plus/core'
219
219
 
220
220
  function LinkWithPrefetch({ id }: { id: string }) {
221
- const hover = useHoverPrefetch(queryKeys.user(id), () => fetch(`/api/users/${id}`).then(r => r.json()))
221
+ const hover = useHoverPrefetch(queryKeys.user(id), () => fetch(`/api/users/${id}`).then(r => r.json()), { hoverDelay: 200, minInterval: 1000 })
222
222
  return <a href={`/user/${id}`} {...hover}>用户详情</a>
223
223
  }
224
224
 
225
225
  function RouterChange() {
226
226
  const prefetch = useRoutePrefetch()
227
227
  useEffect(() => {
228
- prefetch(queryKeys.settings(), () => fetch('/api/settings').then(r => r.json()))
228
+ prefetch(queryKeys.settings(), () => fetch('/api/settings').then(r => r.json()), { minInterval: 1000 })
229
229
  }, [])
230
230
  return null
231
231
  }
232
232
 
233
233
  function SmartCard({ id }: { id: string }) {
234
234
  const { prefetch } = useSmartPrefetch()
235
- return <div onMouseEnter={() => prefetch(queryKeys.user(id), () => fetch(`/api/users/${id}`).then(r => r.json()))}>卡片</div>
235
+ return <div onMouseEnter={() => prefetch(queryKeys.user(id), () => fetch(`/api/users/${id}`).then(r => r.json()), { minInterval: 1000 })}>卡片</div>
236
236
  }
237
237
  ```
238
238
 
@@ -3,6 +3,7 @@ export interface PrefetchOptions {
3
3
  delay?: number;
4
4
  enabled?: boolean;
5
5
  staleTime?: number;
6
+ minInterval?: number;
6
7
  }
7
8
  export interface HoverPrefetchOptions extends PrefetchOptions {
8
9
  hoverDelay?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"usePrefetch.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrefetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAMrE,MAAM,WAAW,eAAe;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AAC1F,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAAG,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AACrF,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAAG,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;AASjI,wBAAgB,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,GAAE,oBAAyB;;;;EAmBtI;AAGD,wBAAgB,gBAAgB,KAEV,KAAK,sBAAsB,QAAQ,WAAW,aAAa,CAAC,KAAK,CAAC,YAAY,eAAe,UAMlH;AAED,wBAAgB,gBAAgB,KAEV,KAAK,qBAAqB,KAAK,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,UAO/H;AAED,wBAAgB,gBAAgB;eASA,KAAK,sBAAsB,QAAQ,WAAW,aAAa,CAAC,KAAK,CAAC,YAAY,eAAe;;;EAU5H;AAED,wBAAgB,sBAAsB,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,QAgBvJ;AAED,wBAAgB,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,QAwBnJ;AAED,wBAAgB,mBAAmB,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,QAkBxJ;AAED,wBAAgB,qBAAqB;gCAIY,MAAM,UAAU,MAAM;;wBAa9B,KAAK,4BAA4B,CAAC,MAAM,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;KAAE;;EASlJ;AAED,wBAAgB,mBAAmB;sBAII,KAAK,sBAAsB,QAAQ,WAAW,aAAa,CAAC,KAAK,CAAC,aAAY,MAAM,GAAG,QAAQ,GAAG,KAAK;;;;EAmB7I"}
1
+ {"version":3,"file":"usePrefetch.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrefetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAMrE,MAAM,WAAW,eAAe;IAAG,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE;AAChH,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAAG,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AACrF,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAAG,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;AASjI,wBAAgB,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,GAAE,oBAAyB;;;;EAwBtI;AAGD,wBAAgB,gBAAgB,KAGV,KAAK,sBAAsB,QAAQ,WAAW,aAAa,CAAC,KAAK,CAAC,YAAY,eAAe,UAUlH;AAED,wBAAgB,gBAAgB,KAEV,KAAK,qBAAqB,KAAK,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,UAO/H;AAED,wBAAgB,gBAAgB;eAUA,KAAK,sBAAsB,QAAQ,WAAW,aAAa,CAAC,KAAK,CAAC,YAAY,eAAe;;;EAa5H;AAED,wBAAgB,sBAAsB,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,eAAe,QAgBvJ;AAED,wBAAgB,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,QAwBnJ;AAED,wBAAgB,mBAAmB,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,QAkBxJ;AAED,wBAAgB,qBAAqB;gCAIY,MAAM,UAAU,MAAM;;wBAa9B,KAAK,4BAA4B,CAAC,MAAM,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;KAAE;;EASlJ;AAED,wBAAgB,mBAAmB;sBAII,KAAK,sBAAsB,QAAQ,WAAW,aAAa,CAAC,KAAK,CAAC,aAAY,MAAM,GAAG,QAAQ,GAAG,KAAK;;;;EAmB7I"}
@@ -12,15 +12,21 @@ function isMissingOrStale(queryClient, queryKey, staleTime) {
12
12
  export function useHoverPrefetch(queryKey, queryFn, options = {}) {
13
13
  const queryClient = useQueryClient();
14
14
  const timeoutRef = useRef(undefined);
15
- const { hoverDelay = 200, enabled = true, staleTime = DEFAULT_STALE_TIME } = options;
15
+ const { hoverDelay = 200, enabled = true, staleTime = DEFAULT_STALE_TIME, minInterval = 1000 } = options;
16
16
  const queryFnRef = useRef(queryFn);
17
17
  useEffect(() => { queryFnRef.current = queryFn; }, [queryFn]);
18
+ const lastPrefetchRef = useRef(new Map());
18
19
  const prefetch = useCallback(() => {
19
20
  if (!enabled)
20
21
  return;
22
+ const keyStr = JSON.stringify(queryKey);
23
+ const last = lastPrefetchRef.current.get(keyStr) ?? 0;
24
+ if (Date.now() - last < minInterval)
25
+ return;
21
26
  if (!isMissingOrStale(queryClient, queryKey, staleTime))
22
27
  return;
23
28
  queryClient.prefetchQuery({ queryKey, queryFn: queryFnRef.current, staleTime });
29
+ lastPrefetchRef.current.set(keyStr, Date.now());
24
30
  }, [queryClient, queryKey, enabled, staleTime]);
25
31
  const handleMouseEnter = useCallback(() => {
26
32
  if (!enabled)
@@ -40,13 +46,19 @@ export function useHoverPrefetch(queryKey, queryFn, options = {}) {
40
46
  }
41
47
  export function useRoutePrefetch() {
42
48
  const queryClient = useQueryClient();
49
+ const lastPrefetchRef = useRef(new Map());
43
50
  return useCallback((queryKey, queryFn, options) => {
44
- const { enabled = true, staleTime = DEFAULT_STALE_TIME } = options || {};
51
+ const { enabled = true, staleTime = DEFAULT_STALE_TIME, minInterval = 1000 } = options || {};
45
52
  if (!enabled)
46
53
  return;
54
+ const keyStr = JSON.stringify(queryKey);
55
+ const last = lastPrefetchRef.current.get(keyStr) ?? 0;
56
+ if (Date.now() - last < minInterval)
57
+ return;
47
58
  if (!isMissingOrStale(queryClient, queryKey, staleTime))
48
59
  return;
49
60
  queryClient.prefetchQuery({ queryKey, queryFn, staleTime });
61
+ lastPrefetchRef.current.set(keyStr, Date.now());
50
62
  }, [queryClient]);
51
63
  }
52
64
  export function useBatchPrefetch() {
@@ -62,6 +74,7 @@ export function useBatchPrefetch() {
62
74
  export function useSmartPrefetch() {
63
75
  const queryClient = useQueryClient();
64
76
  const prefetchedRef = useRef(new Set());
77
+ const lastPrefetchRef = useRef(new Map());
65
78
  const shouldPrefetchQuery = useCallback((queryKey) => {
66
79
  const key = JSON.stringify(queryKey);
67
80
  if (prefetchedRef.current.has(key))
@@ -73,12 +86,16 @@ export function useSmartPrefetch() {
73
86
  const prefetch = useCallback((queryKey, queryFn, options) => {
74
87
  if (!shouldPrefetchQuery(queryKey))
75
88
  return;
76
- const { staleTime = DEFAULT_STALE_TIME } = options || {};
89
+ const { staleTime = DEFAULT_STALE_TIME, minInterval = 1000 } = options || {};
90
+ const keyStr = JSON.stringify(queryKey);
91
+ const last = lastPrefetchRef.current.get(keyStr) ?? 0;
92
+ if (Date.now() - last < minInterval)
93
+ return;
77
94
  if (!isMissingOrStale(queryClient, queryKey, staleTime))
78
95
  return;
79
- const key = JSON.stringify(queryKey);
80
- prefetchedRef.current.add(key);
96
+ prefetchedRef.current.add(keyStr);
81
97
  queryClient.prefetchQuery({ queryKey, queryFn, staleTime });
98
+ lastPrefetchRef.current.set(keyStr, Date.now());
82
99
  }, [queryClient, shouldPrefetchQuery]);
83
100
  const clearPrefetchHistory = useCallback(() => { prefetchedRef.current.clear(); }, []);
84
101
  return { prefetch, shouldPrefetch: !isSlowNetwork(), clearPrefetchHistory };
@@ -1,3 +1,3 @@
1
- export { QueryClient, QueryClientProvider, useQueryClient, skipToken, useIsMutating } from "@tanstack/react-query";
2
- export type { UseQueryOptions, UseSuspenseQueryOptions, UseInfiniteQueryOptions, QueryKey, MutationKey, InfiniteData } from "@tanstack/react-query";
1
+ export { QueryClient, QueryClientProvider, useQueryClient, skipToken, useIsMutating, useIsFetching, useQuery, useInfiniteQuery, useMutation, useSuspenseQuery, useSuspenseInfiniteQuery } from "@tanstack/react-query";
2
+ export type { UseQueryOptions, UseSuspenseQueryOptions, UseInfiniteQueryOptions, QueryKey, MutationKey, InfiniteData, UseQueryResult, UseInfiniteQueryResult, UseMutationResult, DefaultError } from "@tanstack/react-query";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,SAAS,EACT,aAAa,EACd,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,YAAY,EACb,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-query/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,SAAS,EACT,aAAa,EACb,aAAa,EACb,QAAQ,EACR,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACb,MAAM,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- export { QueryClient, QueryClientProvider, useQueryClient, skipToken, useIsMutating } from "@tanstack/react-query";
1
+ export { QueryClient, QueryClientProvider, useQueryClient, skipToken, useIsMutating, useIsFetching, useQuery, useInfiniteQuery, useMutation, useSuspenseQuery, useSuspenseInfiniteQuery } from "@tanstack/react-query";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qiaopeng/tanstack-query-plus",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Enhanced TanStack Query toolkit: defaults, hooks, persistence, offline, utils",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -75,7 +75,7 @@
75
75
  "@tanstack/react-query": "^5",
76
76
  "@tanstack/react-query-persist-client": "^5",
77
77
  "@tanstack/react-query-devtools": "^5",
78
- "react-intersection-observer": "^9"
78
+ "react-intersection-observer": "^9 || ^10"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "@tanstack/react-query-devtools": {