@qiaopeng/tanstack-query-plus 0.2.1 → 0.2.3

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
@@ -126,6 +126,7 @@ function App() {
126
126
  enableOfflineSupport={true} // 启用离线状态监听(默认 true)
127
127
  cacheKey="my-app-cache" // 自定义缓存 key(默认 'tanstack-query-cache')
128
128
  onPersistRestore={() => console.log('缓存已恢复')} // 缓存恢复回调
129
+ onPersistError={(err) => console.error('持久化错误', err)}
129
130
  >
130
131
  <YourApp />
131
132
  </PersistQueryClientProvider>
@@ -150,15 +151,15 @@ function App() {
150
151
  ```typescript
151
152
  {
152
153
  queries: {
153
- staleTime: 30000, // 数据 30 秒内视为新鲜
154
- gcTime: 600000, // 缓存保留 10 分钟
155
- retry: smartRetry, // 智能重试(4xx 不重试,5xx 最多重试 3 次)
156
- retryDelay: exponential, // 指数退避(1s, 2s, 4s...最大 30s)
157
- refetchOnWindowFocus: true, // 窗口聚焦时刷新
158
- refetchOnReconnect: true, // 网络恢复时刷新
154
+ staleTime: 30000,
155
+ gcTime: 600000,
156
+ retry: defaultQueryRetryStrategy,
157
+ retryDelay: exponentialBackoff,
158
+ refetchOnWindowFocus: true,
159
+ refetchOnReconnect: true,
159
160
  },
160
161
  mutations: {
161
- retry: 0, // mutation 默认不重试
162
+ retry: 0,
162
163
  gcTime: 600000,
163
164
  }
164
165
  }
@@ -1040,6 +1041,52 @@ function TodoApp() {
1040
1041
  }
1041
1042
  ```
1042
1043
 
1044
+ ### 7.10 跨分页一致性:前缀失效与缓存对齐
1045
+
1046
+ 在分页列表中,乐观更新通常只更新“当前页”的缓存。为了保证切换到其他页时也看到最新数据,可以使用前缀级失效与跨页缓存对齐:
1047
+
1048
+ 1. 使用统一的域前缀管理 Query Key(例如 `products` 域):
1049
+
1050
+ ```tsx
1051
+ import { createDomainKeyFactory } from '@qiaopeng/tanstack-query-plus/core'
1052
+
1053
+ const productKeys = createDomainKeyFactory('products')
1054
+ const listPrefix = productKeys.lists() // ['tanstack-query', 'products', 'list']
1055
+ ```
1056
+
1057
+ 2. 在 mutation 的乐观更新中启用跨页对齐与前缀失效:
1058
+
1059
+ ```tsx
1060
+ import { useMutation } from '@qiaopeng/tanstack-query-plus/hooks'
1061
+
1062
+ function UpdateProduct({ product }) {
1063
+ const mutation = useMutation({
1064
+ mutationFn: (patch) => api.updateProduct(product.id, patch),
1065
+ optimistic: {
1066
+ queryKey: productKeys.detail(product.id),
1067
+ updater: (oldData, patch) => ({ ...oldData, ...patch }),
1068
+ invalidateScope: 'prefix',
1069
+ invalidatePrefixKey: listPrefix,
1070
+ reconcileCachedPages: true
1071
+ }
1072
+ })
1073
+
1074
+ return (
1075
+ <button onClick={() => mutation.mutate({ title: '新标题' })}>
1076
+ 更新商品
1077
+ </button>
1078
+ )
1079
+ }
1080
+ ```
1081
+
1082
+ 行为说明:
1083
+ - 乐观阶段:先更新当前 key,对已缓存的所有分页列表也应用同样的更新,使切页立即看到新值。
1084
+ - 成功后:对域前缀进行失效,后续展示从服务端获取最终一致数据。
1085
+
1086
+ 注意事项:
1087
+ - 请确保分页查询的 Key 都共享同一前缀(例如通过 `createDomainKeyFactory`),否则前缀失效无法覆盖所有分页。
1088
+ - 在超大列表场景中,跨页对齐可能带来一定开销,可按需开启。
1089
+
1043
1090
  现在你已经掌握了数据变更和乐观更新。接下来,让我们学习如何处理无限滚动和分页场景。
1044
1091
 
1045
1092
  ---
@@ -2479,8 +2526,9 @@ const queueManager = createOfflineQueueManager({
2479
2526
  })
2480
2527
 
2481
2528
  // 注册 mutation 函数(用于恢复队列时执行)
2482
- mutationRegistry.register('updateUser', () => updateUserAPI(data))
2483
- mutationRegistry.register('createPost', () => createPostAPI(data))
2529
+ // 注册函数签名为 () => Promise<unknown>,如需变量请使用闭包或在入队项的 mutationFn 捕获
2530
+ mutationRegistry.register('updateUser', () => updateUserAPI(savedUserData))
2531
+ mutationRegistry.register('createPost', () => createPostAPI(savedPostData))
2484
2532
 
2485
2533
  // 添加操作到队列
2486
2534
  async function handleUpdateUser(userData) {
@@ -2895,7 +2943,7 @@ const { data: adminEmails } = useQuery({
2895
2943
  queryFn: fetchUsers,
2896
2944
  select: selectors.compose(
2897
2945
  selectors.where(u => u.role === 'admin'),
2898
- selectors.field('email')
2946
+ selectors.map(u => u.email)
2899
2947
  ),
2900
2948
  })
2901
2949
  ```
@@ -3260,12 +3308,14 @@ src/
3260
3308
  ```tsx
3261
3309
  // queries/users.ts
3262
3310
  import { useEnhancedQuery } from '@qiaopeng/tanstack-query-plus/hooks'
3263
- import { queryKeys } from './keys'
3311
+ import { createDomainKeyFactory } from '@qiaopeng/tanstack-query-plus/core'
3264
3312
  import { fetchUser, fetchUsers } from '@/api/users'
3265
3313
 
3314
+ const userKeys = createDomainKeyFactory('users')
3315
+
3266
3316
  export function useUser(userId: string) {
3267
3317
  return useEnhancedQuery({
3268
- queryKey: queryKeys.user(userId),
3318
+ queryKey: userKeys.detail(userId),
3269
3319
  queryFn: () => fetchUser(userId),
3270
3320
  enabled: !!userId,
3271
3321
  trackPerformance: true,
@@ -3274,7 +3324,7 @@ export function useUser(userId: string) {
3274
3324
 
3275
3325
  export function useUsers(filters?: UserFilters) {
3276
3326
  return useEnhancedQuery({
3277
- queryKey: queryKeys.users(filters),
3327
+ queryKey: userKeys.list(filters),
3278
3328
  queryFn: () => fetchUsers(filters),
3279
3329
  })
3280
3330
  }
@@ -11,7 +11,7 @@ export function PersistQueryClientProvider({ children, client, cacheKey = "tanst
11
11
  }
12
12
  }, [enableOfflineSupport]);
13
13
  if (enablePersistence) {
14
- const persister = createPersister(cacheKey);
14
+ const persister = createPersister(cacheKey, undefined, _onPersistError);
15
15
  if (!persister) {
16
16
  return _jsx(QueryClientProvider, { client: client, children: children });
17
17
  }
@@ -13,7 +13,7 @@ export declare function createPersistOptions(config?: Partial<PersistOptions>):
13
13
  shouldDehydrateQuery?: (query: Query) => boolean;
14
14
  };
15
15
  };
16
- export declare function createPersister(storageKey?: string, storage?: Storage): Persister | undefined;
16
+ export declare function createPersister(storageKey?: string, storage?: Storage, onError?: (error: Error) => void): Persister | undefined;
17
17
  export declare function clearCache(key?: string): void;
18
18
  export declare function clearExpiredCache(key?: string, maxAge?: number): void;
19
19
  export declare function migrateToIndexedDB(localStorageKey: string | undefined, indexedDBKey: string | undefined, indexedDBStorage: Storage | {
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/features/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAsBvF,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE;AAC1J,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE,CAiBtK;AACD,wBAAgB,eAAe,CAAC,UAAU,SAAyB,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAa7G;AACD,wBAAgB,UAAU,CAAC,GAAG,SAAyB,GAAG,IAAI,CAA0D;AACxH,wBAAgB,iBAAiB,CAAC,GAAG,SAAyB,EAAE,MAAM,SAAsB,GAAG,IAAI,CAQlG;AACD,wBAAsB,kBAAkB,CAAC,eAAe,oBAAyB,EAAE,YAAY,oBAAyB,EAAE,gBAAgB,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAWlO;AACD,wBAAgB,gBAAgB,CAAC,GAAG,SAAyB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CASjJ;AACD,wBAAgB,eAAe,CAAC,GAAG,SAAyB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;CAAE,CAS9L;AACD,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/features/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAsBvF,MAAM,WAAW,cAAc;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE;AAC1J,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,OAAO,CAAC,cAAc,CAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE;QAAE,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAA;KAAE,CAAA;CAAE,CAiBtK;AACD,wBAAgB,eAAe,CAAC,UAAU,SAAyB,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,SAAS,GAAG,SAAS,CAa/I;AACD,wBAAgB,UAAU,CAAC,GAAG,SAAyB,GAAG,IAAI,CAA0D;AACxH,wBAAgB,iBAAiB,CAAC,GAAG,SAAyB,EAAE,MAAM,SAAsB,GAAG,IAAI,CAQlG;AACD,wBAAsB,kBAAkB,CAAC,eAAe,oBAAyB,EAAE,YAAY,oBAAyB,EAAE,gBAAgB,EAAE,OAAO,GAAG;IAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAWlO;AACD,wBAAgB,gBAAgB,CAAC,GAAG,SAAyB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CASjJ;AACD,wBAAgB,eAAe,CAAC,GAAG,SAAyB,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;CAAE,CAS9L;AACD,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC"}
@@ -72,7 +72,7 @@ export function createPersistOptions(config = {}) {
72
72
  }
73
73
  };
74
74
  }
75
- export function createPersister(storageKey = "tanstack-query-cache", storage) {
75
+ export function createPersister(storageKey = "tanstack-query-cache", storage, onError) {
76
76
  if (typeof window === "undefined") {
77
77
  return undefined;
78
78
  }
@@ -86,18 +86,29 @@ export function createPersister(storageKey = "tanstack-query-cache", storage) {
86
86
  persistClient: async (client) => { try {
87
87
  safeStorage.setItem(storageKey, JSON.stringify(client));
88
88
  }
89
- catch { } },
89
+ catch (e) {
90
+ if (onError && e instanceof Error) {
91
+ onError(e);
92
+ }
93
+ } },
90
94
  restoreClient: async () => { try {
91
95
  const raw = safeStorage.getItem(storageKey);
92
96
  return raw ? JSON.parse(raw) : undefined;
93
97
  }
94
- catch {
98
+ catch (e) {
99
+ if (onError && e instanceof Error) {
100
+ onError(e);
101
+ }
95
102
  return undefined;
96
103
  } },
97
104
  removeClient: async () => { try {
98
105
  safeStorage.removeItem(storageKey);
99
106
  }
100
- catch { } }
107
+ catch (e) {
108
+ if (onError && e instanceof Error) {
109
+ onError(e);
110
+ }
111
+ } }
101
112
  };
102
113
  return persister;
103
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useMutation.d.ts","sourceRoot":"","sources":["../../src/hooks/useMutation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useMutation.d.ts","sourceRoot":"","sources":["../../src/hooks/useMutation.ts"],"names":[],"mappings":"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"}
@@ -44,7 +44,14 @@ export function useMutation(options) {
44
44
  }
45
45
  });
46
46
  }
47
- queryClient.setQueryData(optimistic.queryKey, (oldData) => optimistic.updater(oldData, mappedVariables));
47
+ const safeUpdater = (oldData) => {
48
+ const next = optimistic.updater(oldData, mappedVariables);
49
+ return typeof next === "undefined" ? oldData : next;
50
+ };
51
+ queryClient.setQueryData(optimistic.queryKey, safeUpdater);
52
+ if (optimistic.reconcileCachedPages && optimistic.invalidatePrefixKey) {
53
+ queryClient.setQueriesData({ queryKey: optimistic.invalidatePrefixKey }, safeUpdater);
54
+ }
48
55
  const mutateCallback = onMutate;
49
56
  const userContext = onMutate ? await mutateCallback(variables) : undefined;
50
57
  return { previousData, userContext };
@@ -69,7 +76,8 @@ export function useMutation(options) {
69
76
  }
70
77
  };
71
78
  mutationConfig.onSuccess = (data, variables, context) => {
72
- queryClient.invalidateQueries({ queryKey: optimistic.queryKey });
79
+ const scope = optimistic.invalidateScope === "prefix" && optimistic.invalidatePrefixKey ? optimistic.invalidatePrefixKey : optimistic.queryKey;
80
+ queryClient.invalidateQueries({ queryKey: scope });
73
81
  if (onSuccess) {
74
82
  const successCallback = onSuccess;
75
83
  successCallback(data, variables, context?.userContext);
@@ -18,6 +18,9 @@ export interface MutationOptions<TData, TError, TVariables, TContext = unknown>
18
18
  enabled?: boolean;
19
19
  fieldMapping?: Record<string, string>;
20
20
  rollback?: <TQueryData = unknown>(previousData: TQueryData, error: Error) => void;
21
+ invalidateScope?: "exact" | "prefix";
22
+ invalidatePrefixKey?: QueryKey;
23
+ reconcileCachedPages?: boolean;
21
24
  };
22
25
  }
23
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,MAAM,WAAW,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO;IAAI,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE;AAC9I,MAAM,WAAW,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAE,SAAQ,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC7I,UAAU,CAAC,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,SAAS,EAAE,UAAU,KAAK,UAAU,GAAG,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;KAAE,CAAC;CACrS"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,MAAM,WAAW,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO;IAAI,YAAY,CAAC,EAAE,KAAK,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE;AAC9I,MAAM,WAAW,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAE,SAAQ,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC7I,UAAU,CAAC,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,OAAO,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,OAAO,EAAE,UAAU,GAAG,SAAS,EAAE,SAAS,EAAE,UAAU,KAAK,UAAU,GAAG,SAAS,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,GAAG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;QAAC,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;QAAC,mBAAmB,CAAC,EAAE,QAAQ,CAAC;QAAC,oBAAoB,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3Y"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qiaopeng/tanstack-query-plus",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Enhanced TanStack Query toolkit: defaults, hooks, persistence, offline, utils",
5
5
  "author": "qiaopeng",
6
6
  "license": "MIT",