@qiaopeng/tanstack-query-plus 0.5.8 → 0.5.10

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.
Files changed (250) hide show
  1. package/README.md +155 -95
  2. package/dist/{types/base.d.ts → base-CHnwqfyz.d.cts} +12 -14
  3. package/dist/base-CHnwqfyz.d.ts +52 -0
  4. package/dist/chunk-52ZO6Y67.cjs +1121 -0
  5. package/dist/chunk-52ZO6Y67.cjs.map +1 -0
  6. package/dist/chunk-5J6OXSLW.cjs +36 -0
  7. package/dist/chunk-5J6OXSLW.cjs.map +1 -0
  8. package/dist/chunk-6MAYHLTE.cjs +310 -0
  9. package/dist/chunk-6MAYHLTE.cjs.map +1 -0
  10. package/dist/chunk-ADS2QTMP.js +144 -0
  11. package/dist/chunk-ADS2QTMP.js.map +1 -0
  12. package/dist/chunk-APXNNHBD.cjs +374 -0
  13. package/dist/chunk-APXNNHBD.cjs.map +1 -0
  14. package/dist/chunk-AXMWOGNX.js +134 -0
  15. package/dist/chunk-AXMWOGNX.js.map +1 -0
  16. package/dist/chunk-B4KO3K3E.cjs +521 -0
  17. package/dist/chunk-B4KO3K3E.cjs.map +1 -0
  18. package/dist/chunk-BK3OTIBD.cjs +15 -0
  19. package/dist/chunk-BK3OTIBD.cjs.map +1 -0
  20. package/dist/chunk-BYAOQALW.js +13 -0
  21. package/dist/chunk-BYAOQALW.js.map +1 -0
  22. package/dist/chunk-CRTVS7VI.cjs +162 -0
  23. package/dist/chunk-CRTVS7VI.cjs.map +1 -0
  24. package/dist/chunk-EXITP7QO.js +288 -0
  25. package/dist/chunk-EXITP7QO.js.map +1 -0
  26. package/dist/chunk-GMO3PRZZ.js +565 -0
  27. package/dist/chunk-GMO3PRZZ.js.map +1 -0
  28. package/dist/chunk-HRO2DWKZ.js +12 -0
  29. package/dist/chunk-HRO2DWKZ.js.map +1 -0
  30. package/dist/chunk-JHDKUQSB.js +1069 -0
  31. package/dist/chunk-JHDKUQSB.js.map +1 -0
  32. package/dist/chunk-JN2Y6RSY.js +23 -0
  33. package/dist/chunk-JN2Y6RSY.js.map +1 -0
  34. package/dist/chunk-JRJSKRZW.cjs +29 -0
  35. package/dist/chunk-JRJSKRZW.cjs.map +1 -0
  36. package/dist/chunk-KC62H4VJ.js +123 -0
  37. package/dist/chunk-KC62H4VJ.js.map +1 -0
  38. package/dist/chunk-LHEHSLD5.js +31 -0
  39. package/dist/chunk-LHEHSLD5.js.map +1 -0
  40. package/dist/chunk-N4264P7N.cjs +156 -0
  41. package/dist/chunk-N4264P7N.cjs.map +1 -0
  42. package/dist/chunk-NF5QYPYC.cjs +133 -0
  43. package/dist/chunk-NF5QYPYC.cjs.map +1 -0
  44. package/dist/chunk-OFLCHKKE.cjs +28 -0
  45. package/dist/chunk-OFLCHKKE.cjs.map +1 -0
  46. package/dist/chunk-PCNSWVA5.cjs +602 -0
  47. package/dist/chunk-PCNSWVA5.cjs.map +1 -0
  48. package/dist/chunk-STOMAA2X.js +85 -0
  49. package/dist/chunk-STOMAA2X.js.map +1 -0
  50. package/dist/chunk-UVF5S6LX.cjs +15 -0
  51. package/dist/chunk-UVF5S6LX.cjs.map +1 -0
  52. package/dist/chunk-WEIXCDCA.cjs +90 -0
  53. package/dist/chunk-WEIXCDCA.cjs.map +1 -0
  54. package/dist/chunk-X3ZTSLBQ.js +355 -0
  55. package/dist/chunk-X3ZTSLBQ.js.map +1 -0
  56. package/dist/chunk-YEV73J4J.js +504 -0
  57. package/dist/chunk-YEV73J4J.js.map +1 -0
  58. package/dist/chunk-YW5PNTRU.cjs +14 -0
  59. package/dist/chunk-YW5PNTRU.cjs.map +1 -0
  60. package/dist/chunk-ZNXSWUIS.js +12 -0
  61. package/dist/chunk-ZNXSWUIS.js.map +1 -0
  62. package/dist/chunk-ZUEMBY4W.js +21 -0
  63. package/dist/chunk-ZUEMBY4W.js.map +1 -0
  64. package/dist/components/index.cjs +60 -0
  65. package/dist/components/index.cjs.map +1 -0
  66. package/dist/components/index.d.cts +43 -0
  67. package/dist/components/index.d.ts +43 -4
  68. package/dist/components/index.js +3 -4
  69. package/dist/components/index.js.map +1 -0
  70. package/dist/core/devtools.cjs +25 -0
  71. package/dist/core/devtools.cjs.map +1 -0
  72. package/dist/core/devtools.d.cts +17 -0
  73. package/dist/core/devtools.d.ts +9 -7
  74. package/dist/core/devtools.js +4 -16
  75. package/dist/core/devtools.js.map +1 -0
  76. package/dist/core/index.cjs +220 -0
  77. package/dist/core/index.cjs.map +1 -0
  78. package/dist/core/index.d.cts +196 -0
  79. package/dist/core/index.d.ts +196 -9
  80. package/dist/core/index.js +7 -8
  81. package/dist/core/index.js.map +1 -0
  82. package/dist/features/index.cjs +76 -0
  83. package/dist/features/index.cjs.map +1 -0
  84. package/dist/features/index.d.cts +86 -0
  85. package/dist/features/index.d.ts +86 -4
  86. package/dist/features/index.js +7 -3
  87. package/dist/features/index.js.map +1 -0
  88. package/dist/hooks/index.cjs +209 -0
  89. package/dist/hooks/index.cjs.map +1 -0
  90. package/dist/hooks/index.d.cts +377 -0
  91. package/dist/hooks/index.d.ts +377 -10
  92. package/dist/hooks/index.js +8 -9
  93. package/dist/hooks/index.js.map +1 -0
  94. package/dist/hooks/useInViewPrefetch.cjs +33 -0
  95. package/dist/hooks/useInViewPrefetch.cjs.map +1 -0
  96. package/dist/hooks/useInViewPrefetch.d.cts +12 -0
  97. package/dist/hooks/useInViewPrefetch.d.ts +6 -4
  98. package/dist/hooks/useInViewPrefetch.js +30 -20
  99. package/dist/hooks/useInViewPrefetch.js.map +1 -0
  100. package/dist/index.cjs +811 -0
  101. package/dist/index.cjs.map +1 -0
  102. package/dist/index.d.cts +36 -0
  103. package/dist/index.d.ts +36 -8
  104. package/dist/index.js +89 -7
  105. package/dist/index.js.map +1 -0
  106. package/dist/{types/offline.d.ts → offline-DVPtgoAS.d.ts} +15 -13
  107. package/dist/offline-xxeA_-6V.d.cts +99 -0
  108. package/dist/persistence-MRtkmhqq.d.cts +216 -0
  109. package/dist/persistence-tIrEb0pR.d.ts +216 -0
  110. package/dist/react-query/index.cjs +52 -0
  111. package/dist/react-query/index.cjs.map +1 -0
  112. package/dist/react-query/index.d.cts +1 -0
  113. package/dist/react-query/index.d.ts +1 -3
  114. package/dist/react-query/index.js +3 -1
  115. package/dist/react-query/index.js.map +1 -0
  116. package/dist/types/index.cjs +43 -0
  117. package/dist/types/index.cjs.map +1 -0
  118. package/dist/types/index.d.cts +157 -0
  119. package/dist/types/index.d.ts +116 -12
  120. package/dist/types/index.js +6 -8
  121. package/dist/types/index.js.map +1 -0
  122. package/dist/utils/index.cjs +234 -0
  123. package/dist/utils/index.cjs.map +1 -0
  124. package/dist/utils/index.d.cts +272 -0
  125. package/dist/utils/index.d.ts +272 -10
  126. package/dist/utils/index.js +9 -9
  127. package/dist/utils/index.js.map +1 -0
  128. package/package.json +13 -3
  129. package/dist/PersistQueryClientProvider.d.ts +0 -22
  130. package/dist/PersistQueryClientProvider.d.ts.map +0 -1
  131. package/dist/PersistQueryClientProvider.js +0 -47
  132. package/dist/components/LoadingFallback.d.ts +0 -16
  133. package/dist/components/LoadingFallback.d.ts.map +0 -1
  134. package/dist/components/LoadingFallback.js +0 -27
  135. package/dist/components/QueryErrorBoundary.d.ts +0 -12
  136. package/dist/components/QueryErrorBoundary.d.ts.map +0 -1
  137. package/dist/components/QueryErrorBoundary.js +0 -9
  138. package/dist/components/SuspenseWrapper.d.ts +0 -14
  139. package/dist/components/SuspenseWrapper.d.ts.map +0 -1
  140. package/dist/components/SuspenseWrapper.js +0 -9
  141. package/dist/components/index.d.ts.map +0 -1
  142. package/dist/components/internal/ErrorBoundary.d.ts +0 -27
  143. package/dist/components/internal/ErrorBoundary.d.ts.map +0 -1
  144. package/dist/components/internal/ErrorBoundary.js +0 -37
  145. package/dist/core/config.d.ts +0 -80
  146. package/dist/core/config.d.ts.map +0 -1
  147. package/dist/core/config.js +0 -321
  148. package/dist/core/devtools.d.ts.map +0 -1
  149. package/dist/core/env.d.ts +0 -4
  150. package/dist/core/env.d.ts.map +0 -1
  151. package/dist/core/env.js +0 -26
  152. package/dist/core/focusManager.d.ts +0 -33
  153. package/dist/core/focusManager.d.ts.map +0 -1
  154. package/dist/core/focusManager.js +0 -122
  155. package/dist/core/index.d.ts.map +0 -1
  156. package/dist/core/keys.d.ts +0 -59
  157. package/dist/core/keys.d.ts.map +0 -1
  158. package/dist/core/keys.js +0 -107
  159. package/dist/core/queryOptions.d.ts +0 -19
  160. package/dist/core/queryOptions.d.ts.map +0 -1
  161. package/dist/core/queryOptions.js +0 -44
  162. package/dist/features/index.d.ts.map +0 -1
  163. package/dist/features/offline.d.ts +0 -48
  164. package/dist/features/offline.d.ts.map +0 -1
  165. package/dist/features/offline.js +0 -269
  166. package/dist/features/persistence.d.ts +0 -36
  167. package/dist/features/persistence.d.ts.map +0 -1
  168. package/dist/features/persistence.js +0 -186
  169. package/dist/hooks/batchQueries.d.ts +0 -129
  170. package/dist/hooks/batchQueries.d.ts.map +0 -1
  171. package/dist/hooks/batchQueries.js +0 -301
  172. package/dist/hooks/index.d.ts.map +0 -1
  173. package/dist/hooks/useDataGuardMutation.d.ts +0 -39
  174. package/dist/hooks/useDataGuardMutation.d.ts.map +0 -1
  175. package/dist/hooks/useDataGuardMutation.js +0 -151
  176. package/dist/hooks/useDataGuardQuery.d.ts +0 -28
  177. package/dist/hooks/useDataGuardQuery.d.ts.map +0 -1
  178. package/dist/hooks/useDataGuardQuery.js +0 -71
  179. package/dist/hooks/useFocusManager.d.ts +0 -41
  180. package/dist/hooks/useFocusManager.d.ts.map +0 -1
  181. package/dist/hooks/useFocusManager.js +0 -109
  182. package/dist/hooks/useInViewPrefetch.d.ts.map +0 -1
  183. package/dist/hooks/useInfiniteQuery.d.ts +0 -33
  184. package/dist/hooks/useInfiniteQuery.d.ts.map +0 -1
  185. package/dist/hooks/useInfiniteQuery.js +0 -61
  186. package/dist/hooks/useMutation.d.ts +0 -25
  187. package/dist/hooks/useMutation.d.ts.map +0 -1
  188. package/dist/hooks/useMutation.js +0 -180
  189. package/dist/hooks/usePrefetch.d.ts +0 -54
  190. package/dist/hooks/usePrefetch.d.ts.map +0 -1
  191. package/dist/hooks/usePrefetch.js +0 -229
  192. package/dist/hooks/useQuery.d.ts +0 -21
  193. package/dist/hooks/useQuery.d.ts.map +0 -1
  194. package/dist/hooks/useQuery.js +0 -46
  195. package/dist/hooks/useSuspenseQuery.d.ts +0 -11
  196. package/dist/hooks/useSuspenseQuery.d.ts.map +0 -1
  197. package/dist/hooks/useSuspenseQuery.js +0 -19
  198. package/dist/index.d.ts.map +0 -1
  199. package/dist/react-query/index.d.ts.map +0 -1
  200. package/dist/types/base.d.ts.map +0 -1
  201. package/dist/types/base.js +0 -26
  202. package/dist/types/dataGuard.d.ts +0 -69
  203. package/dist/types/dataGuard.d.ts.map +0 -1
  204. package/dist/types/dataGuard.js +0 -10
  205. package/dist/types/index.d.ts.map +0 -1
  206. package/dist/types/infinite.d.ts +0 -39
  207. package/dist/types/infinite.d.ts.map +0 -1
  208. package/dist/types/infinite.js +0 -1
  209. package/dist/types/offline.d.ts.map +0 -1
  210. package/dist/types/offline.js +0 -8
  211. package/dist/types/optimistic.d.ts +0 -126
  212. package/dist/types/optimistic.d.ts.map +0 -1
  213. package/dist/types/optimistic.js +0 -7
  214. package/dist/types/persistence.d.ts +0 -9
  215. package/dist/types/persistence.d.ts.map +0 -1
  216. package/dist/types/persistence.js +0 -1
  217. package/dist/types/selectors.d.ts +0 -11
  218. package/dist/types/selectors.d.ts.map +0 -1
  219. package/dist/types/selectors.js +0 -1
  220. package/dist/types/suspense.d.ts +0 -67
  221. package/dist/types/suspense.d.ts.map +0 -1
  222. package/dist/types/suspense.js +0 -1
  223. package/dist/utils/dataGuard.d.ts +0 -37
  224. package/dist/utils/dataGuard.d.ts.map +0 -1
  225. package/dist/utils/dataGuard.js +0 -257
  226. package/dist/utils/fieldMapper.d.ts +0 -9
  227. package/dist/utils/fieldMapper.d.ts.map +0 -1
  228. package/dist/utils/fieldMapper.js +0 -27
  229. package/dist/utils/index.d.ts.map +0 -1
  230. package/dist/utils/network.d.ts +0 -9
  231. package/dist/utils/network.d.ts.map +0 -1
  232. package/dist/utils/network.js +0 -43
  233. package/dist/utils/optimisticUtils.d.ts +0 -45
  234. package/dist/utils/optimisticUtils.d.ts.map +0 -1
  235. package/dist/utils/optimisticUtils.js +0 -116
  236. package/dist/utils/placeholderData.d.ts +0 -3
  237. package/dist/utils/placeholderData.d.ts.map +0 -1
  238. package/dist/utils/placeholderData.js +0 -28
  239. package/dist/utils/prefetchManager.d.ts +0 -111
  240. package/dist/utils/prefetchManager.d.ts.map +0 -1
  241. package/dist/utils/prefetchManager.js +0 -246
  242. package/dist/utils/queryKey.d.ts +0 -24
  243. package/dist/utils/queryKey.d.ts.map +0 -1
  244. package/dist/utils/queryKey.js +0 -77
  245. package/dist/utils/selectors.d.ts +0 -30
  246. package/dist/utils/selectors.d.ts.map +0 -1
  247. package/dist/utils/selectors.js +0 -18
  248. package/dist/utils/storage.d.ts +0 -7
  249. package/dist/utils/storage.d.ts.map +0 -1
  250. package/dist/utils/storage.js +0 -84
package/README.md CHANGED
@@ -12,15 +12,16 @@
12
12
  6. [第四步:管理 Query Key](#6-第四步管理-query-key)
13
13
  7. [第五步:数据变更与乐观更新](#7-第五步数据变更与乐观更新)
14
14
  8. [第六步:无限滚动与分页](#8-第六步无限滚动与分页)
15
- 9. [第七步:批量查询与仪表盘](#9-第七步批量查询与仪表盘)
16
- 10. [第八步:智能预取](#10-第八步智能预取)
17
- 11. [第九步:Suspense 模式](#11-第九步suspense-模式)
18
- 12. [第十步:离线支持与持久化](#12-第十步离线支持与持久化)
19
- 13. [第十一步:数据防护与安全](#13-第十一步数据防护与安全)
20
- 14. [第十二步:焦点管理](#14-第十二步焦点管理)
21
- 15. [第十三步:工具函数与选择器](#15-第十三步工具函数与选择器)
22
- 16. [最佳实践与常见问题](#16-最佳实践与常见问题)
23
- 17. [API 索引](#17-api-索引)
15
+ 9. [第七步:全局状态与 Mutation 监控](#9-第七步全局状态与-mutation-监控)
16
+ 10. [第八步:批量查询与仪表盘](#10-第八步批量查询与仪表盘)
17
+ 11. [第九步:智能预取](#11-第九步智能预取)
18
+ 12. [第十步:Suspense 模式与 SSR](#12-第十步suspense-模式与-ssr)
19
+ 13. [第十一步:离线支持与持久化](#13-第十一步离线支持与持久化)
20
+ 14. [第十二步:数据防护与安全](#14-第十二步数据防护与安全)
21
+ 15. [第十三步:焦点管理](#15-第十三步焦点管理)
22
+ 16. [第十四步:工具函数与选择器](#16-第十四步工具函数与选择器)
23
+ 17. [最佳实践与常见问题](#17-最佳实践与常见问题)
24
+ 18. [API 索引](#18-api-索引)
24
25
 
25
26
  ---
26
27
 
@@ -295,9 +296,11 @@ function App() {
295
296
  retryDelay: exponentialBackoff,
296
297
  refetchOnWindowFocus: true,
297
298
  refetchOnReconnect: true,
299
+ refetchOnMount: true,
298
300
  },
299
301
  mutations: {
300
302
  retry: 0, // Mutation 默认不重试
303
+ retryDelay: exponentialBackoff,
301
304
  gcTime: 600000,
302
305
  }
303
306
  }
@@ -325,7 +328,13 @@ function App() {
325
328
  import { getConfigByEnvironment } from '@qiaopeng/tanstack-query-plus/core'
326
329
 
327
330
  // 根据环境自动选择配置
328
- const config = getConfigByEnvironment(process.env.NODE_ENV)
331
+ const env =
332
+ process.env.NODE_ENV === 'production'
333
+ ? 'production'
334
+ : process.env.NODE_ENV === 'test'
335
+ ? 'test'
336
+ : 'development'
337
+ const config = getConfigByEnvironment(env)
329
338
  const queryClient = new QueryClient({ defaultOptions: config })
330
339
  ```
331
340
 
@@ -340,6 +349,8 @@ const queryClient = new QueryClient({ defaultOptions: config })
340
349
 
341
350
  *智能重试:4XX 不重试,5XX 最多 1 次,网络错误最多 2 次
342
351
 
352
+ 补充:还支持 `getConfigByEnvironment('longCache')` 与 `getConfigByEnvironment('realtime')` 两种预设,分别适用于“长缓存”与“高实时”场景。
353
+
343
354
  ### 3.5 自定义重试策略
344
355
 
345
356
  如果默认的重试策略不满足你的需求,可以使用 `createSafeRetryStrategy` 和 `createErrorSafeConfig` 来自定义:
@@ -1129,13 +1140,21 @@ batchDelete.mutate(['id1', 'id2', 'id3'])
1129
1140
  2. 使用离线队列在恢复网络后批量执行(稳健且可持久化):
1130
1141
 
1131
1142
  ```tsx
1132
- import { createOfflineQueueManager, mutationRegistry } from '@qiaopeng/tanstack-query-plus/features'
1143
+ import { createOfflineQueueManager, mutationRegistry, serializeMutationKey } from '@qiaopeng/tanstack-query-plus/features'
1144
+ import { MutationOperationType } from '@qiaopeng/tanstack-query-plus/types'
1133
1145
 
1134
1146
  const queue = createOfflineQueueManager({ storageKey: 'todo-ops', concurrency: 3 })
1135
1147
 
1136
- function registerDelete(id: string) {
1137
- mutationRegistry.register(['todos','delete',id].join('-'), () => api.deleteTodo(id))
1138
- queue.add({ mutationKey: ['todos','delete',id], mutationFn: () => api.deleteTodo(id), priority: 1 })
1148
+ async function registerDelete(id: string) {
1149
+ const key = serializeMutationKey(['todos', 'delete', id])
1150
+ mutationRegistry.register(key, () => api.deleteTodo(id))
1151
+ await queue.add({
1152
+ type: MutationOperationType.DELETE,
1153
+ mutationKey: ['todos', 'delete', id],
1154
+ variables: { id },
1155
+ mutationFn: () => api.deleteTodo(id),
1156
+ priority: 1
1157
+ })
1139
1158
  }
1140
1159
  ```
1141
1160
 
@@ -1613,7 +1632,62 @@ const result = useEnhancedInfiniteQuery(customOptions)
1613
1632
 
1614
1633
  ---
1615
1634
 
1616
- ## 9. 第七步:批量查询与仪表盘
1635
+ ## 9. 第七步:全局状态与 Mutation 监控
1636
+
1637
+ 在复杂的应用中,你可能需要监控全局的加载状态,或者获取正在进行的 Mutation 进度。本库补全了 v5 的状态监控 Hooks。
1638
+
1639
+ ### 9.1 监控全局加载状态
1640
+
1641
+ 使用 `useIsFetching` 和 `useIsMutating` 可以实时感知后台活动:
1642
+
1643
+ ```tsx
1644
+ import { useIsFetching, useIsMutating } from '@qiaopeng/tanstack-query-plus/hooks'
1645
+
1646
+ function GlobalLoadingIndicator() {
1647
+ const isFetching = useIsFetching() // 正在进行的 Query 数量
1648
+ const isMutating = useIsMutating() // 正在进行的 Mutation 数量
1649
+
1650
+ if (!isFetching && !isMutating) return null
1651
+
1652
+ return (
1653
+ <div className="fixed top-0 right-0 p-4">
1654
+ {isFetching > 0 && <span>数据加载中...</span>}
1655
+ {isMutating > 0 && <span>后台同步中...</span>}
1656
+ </div>
1657
+ )
1658
+ }
1659
+ ```
1660
+
1661
+ ### 9.2 监控 Mutation 详细状态
1662
+
1663
+ `useMutationState` 允许你订阅 Mutation 缓存,获取特定任务的进度或结果:
1664
+
1665
+ ```tsx
1666
+ import { useMutationState } from '@qiaopeng/tanstack-query-plus/hooks'
1667
+
1668
+ function UploadManager() {
1669
+ // 获取所有 ['upload'] 相关的 mutation 状态
1670
+ const uploads = useMutationState({
1671
+ filters: { mutationKey: ['upload'], status: 'pending' },
1672
+ select: (mutation) => mutation.state.variables,
1673
+ })
1674
+
1675
+ return (
1676
+ <div>
1677
+ <h3>正在上传 ({uploads.length})</h3>
1678
+ <ul>
1679
+ {uploads.map((file, i) => (
1680
+ <li key={i}>{file.name} 正在传输...</li>
1681
+ ))}
1682
+ </ul>
1683
+ </div>
1684
+ )
1685
+ }
1686
+ ```
1687
+
1688
+ ---
1689
+
1690
+ ## 10. 第八步:批量查询与仪表盘
1617
1691
 
1618
1692
 
1619
1693
  在仪表盘、数据概览等场景中,我们经常需要同时发起多个查询。本库提供了强大的批量查询功能,包括统计信息、批量操作和错误聚合。
@@ -2266,74 +2340,49 @@ function ProductBrowser() {
2266
2340
 
2267
2341
  ---
2268
2342
 
2269
- ## 11. 第九步:Suspense 模式
2343
+ ## 12. 第十步:Suspense 模式与 SSR
2270
2344
 
2345
+ React Suspense 提供了声明式的加载处理。本库不仅支持增强的 Suspense Hooks,还提供了完善的 SSR 水合支持。
2271
2346
 
2272
- React Suspense 是一种声明式的加载状态处理方式。配合 TanStack Query 的 Suspense 模式,可以让组件代码更简洁,不再需要手动处理 `isLoading` 状态。
2347
+ ### 12.1 基础 Suspense 查询
2273
2348
 
2274
- ### 11.1 传统模式 vs Suspense 模式
2349
+ `useEnhancedSuspenseQuery` 保证 `data` 始终存在,省去非空判断:
2275
2350
 
2276
- **传统模式:**
2277
2351
  ```tsx
2278
- function UserProfile({ userId }) {
2279
- const { data, isLoading, isError, error } = useQuery({
2280
- queryKey: ['user', userId],
2281
- queryFn: () => fetchUser(userId),
2282
- })
2283
-
2284
- if (isLoading) return <Loading />
2285
- if (isError) return <Error message={error.message} />
2286
-
2287
- return <div>{data.name}</div>
2288
- }
2289
- ```
2352
+ import { useEnhancedSuspenseQuery } from '@qiaopeng/tanstack-query-plus/hooks'
2290
2353
 
2291
- **Suspense 模式:**
2292
- ```tsx
2293
2354
  function UserProfile({ userId }) {
2294
- // 数据一定存在,不需要处理 loading 状态
2295
- const { data } = useSuspenseQuery({
2355
+ const { data } = useEnhancedSuspenseQuery({
2296
2356
  queryKey: ['user', userId],
2297
2357
  queryFn: () => fetchUser(userId),
2298
2358
  })
2299
2359
 
2300
2360
  return <div>{data.name}</div>
2301
2361
  }
2302
-
2303
- // 在父组件处理 loading 和 error
2304
- function UserPage({ userId }) {
2305
- return (
2306
- <Suspense fallback={<Loading />}>
2307
- <ErrorBoundary fallback={<Error />}>
2308
- <UserProfile userId={userId} />
2309
- </ErrorBoundary>
2310
- </Suspense>
2311
- )
2312
- }
2313
2362
  ```
2314
2363
 
2315
- ### 11.2 使用增强 Suspense 查询
2364
+ ### 12.2 SSR 水合支持
2365
+
2366
+ 在 Next.js (App Router) 或其他 SSR 框架中,使用 `HydrationBoundary` 进行注水:
2316
2367
 
2317
2368
  ```tsx
2318
- import { useEnhancedSuspenseQuery } from '@qiaopeng/tanstack-query-plus/hooks'
2369
+ // Server Component
2370
+ import { dehydrate, QueryClient } from '@qiaopeng/tanstack-query-plus'
2371
+ import { HydrationBoundary } from '@qiaopeng/tanstack-query-plus/components'
2319
2372
 
2320
- function UserData({ userId }) {
2321
- const { data } = useEnhancedSuspenseQuery({
2322
- queryKey: ['user', userId],
2323
- queryFn: () => fetchUser(userId),
2324
- })
2373
+ export default async function Page() {
2374
+ const queryClient = new QueryClient()
2375
+ await queryClient.prefetchQuery({ queryKey: ['posts'], queryFn: fetchPosts })
2325
2376
 
2326
- // data 一定存在,TypeScript 类型也是非空的
2327
2377
  return (
2328
- <div>
2329
- <h1>{data.name}</h1>
2330
- <p>{data.email}</p>
2331
- </div>
2378
+ <HydrationBoundary state={dehydrate(queryClient)}>
2379
+ <PostsList />
2380
+ </HydrationBoundary>
2332
2381
  )
2333
2382
  }
2334
2383
  ```
2335
2384
 
2336
- ### 11.3 使用 SuspenseWrapper 组件
2385
+ ### 12.3 使用 SuspenseWrapper 组件
2337
2386
 
2338
2387
  本库提供了 `SuspenseWrapper` 和 `QuerySuspenseWrapper` 组件,它们组合了 Suspense 和 ErrorBoundary:
2339
2388
 
@@ -2710,7 +2759,8 @@ console.log({
2710
2759
  对于需要在离线时也能操作的应用,可以使用离线队列管理器:
2711
2760
 
2712
2761
  ```tsx
2713
- import { createOfflineQueueManager, mutationRegistry } from '@qiaopeng/tanstack-query-plus/features'
2762
+ import { createOfflineQueueManager, isOnline, mutationRegistry, serializeMutationKey } from '@qiaopeng/tanstack-query-plus/features'
2763
+ import { MutationOperationType } from '@qiaopeng/tanstack-query-plus/types'
2714
2764
 
2715
2765
  // 创建队列管理器
2716
2766
  const queueManager = createOfflineQueueManager({
@@ -2723,15 +2773,17 @@ const queueManager = createOfflineQueueManager({
2723
2773
 
2724
2774
  // 注册 mutation 函数(用于恢复队列时执行)
2725
2775
  // 注册函数签名为 () => Promise<unknown>,如需变量请使用闭包或在入队项的 mutationFn 捕获
2726
- mutationRegistry.register('updateUser', () => updateUserAPI(savedUserData))
2727
- mutationRegistry.register('createPost', () => createPostAPI(savedPostData))
2776
+ mutationRegistry.register(serializeMutationKey(['updateUser']), () => updateUserAPI(savedUserData))
2777
+ mutationRegistry.register(serializeMutationKey(['createPost']), () => createPostAPI(savedPostData))
2728
2778
 
2729
2779
  // 添加操作到队列
2730
2780
  async function handleUpdateUser(userData) {
2731
2781
  if (!isOnline()) {
2732
2782
  // 离线时添加到队列
2733
2783
  await queueManager.add({
2784
+ type: MutationOperationType.UPDATE,
2734
2785
  mutationKey: ['updateUser'],
2786
+ variables: userData,
2735
2787
  mutationFn: () => updateUserAPI(userData),
2736
2788
  priority: 1, // 优先级(数字越大越优先)
2737
2789
  })
@@ -2772,6 +2824,7 @@ queueManager.destroy()
2772
2824
  ```tsx
2773
2825
  import { useState, useEffect } from 'react'
2774
2826
  import { createOfflineQueueManager } from '@qiaopeng/tanstack-query-plus/features'
2827
+ import { MutationOperationType } from '@qiaopeng/tanstack-query-plus/types'
2775
2828
  import { useEnhancedQuery } from '@qiaopeng/tanstack-query-plus/hooks'
2776
2829
  import { useQueryClient, usePersistenceStatus } from '@qiaopeng/tanstack-query-plus'
2777
2830
 
@@ -2817,7 +2870,9 @@ function TodoApp() {
2817
2870
  if (!networkStatus) {
2818
2871
  // 离线:添加到队列
2819
2872
  await offlineQueue.add({
2873
+ type: MutationOperationType.CREATE,
2820
2874
  mutationKey: ['addTodo'],
2875
+ variables: todoData,
2821
2876
  mutationFn: () => api.createTodo(todoData),
2822
2877
  priority: 1,
2823
2878
  })
@@ -3675,7 +3730,13 @@ function UserProfile({ userId }) {
3675
3730
  import { QueryClient } from '@qiaopeng/tanstack-query-plus'
3676
3731
  import { getConfigByEnvironment, ensureBestPractices } from '@qiaopeng/tanstack-query-plus/core'
3677
3732
 
3678
- const baseConfig = getConfigByEnvironment(process.env.NODE_ENV)
3733
+ const env =
3734
+ process.env.NODE_ENV === 'production'
3735
+ ? 'production'
3736
+ : process.env.NODE_ENV === 'test'
3737
+ ? 'test'
3738
+ : 'development'
3739
+ const baseConfig = getConfigByEnvironment(env)
3679
3740
 
3680
3741
  // 确保配置符合最佳实践
3681
3742
  const config = ensureBestPractices({
@@ -3751,12 +3812,12 @@ function useUser(userId: string): EnhancedQueryResult<User, ApiError> {
3751
3812
  }
3752
3813
 
3753
3814
  // 类型安全的 mutation
3754
- function useUpdateUser() {
3815
+ function useUpdateUser(userId: string) {
3755
3816
  return useMutation<User, ApiError, Partial<User>>({
3756
- mutationFn: (data) => updateUser(data),
3817
+ mutationFn: (patch) => updateUser(userId, patch),
3757
3818
  optimistic: {
3758
- queryKey: ['user', data.id],
3759
- updater: (old, newData) => ({ ...old, ...newData }),
3819
+ queryKey: ['user', userId],
3820
+ updater: (old, patch) => (old ? ({ ...old, ...patch }) : old),
3760
3821
  },
3761
3822
  })
3762
3823
  }
@@ -3886,32 +3947,6 @@ useEnhancedQuery({
3886
3947
  3. **处理认证过期**:在全局错误处理中处理 401 错误
3887
3948
  4. **清理敏感缓存**:用户登出时清除缓存
3888
3949
 
3889
- ---
3890
-
3891
- ## 总结
3892
-
3893
- 恭喜你完成了本教程!现在你已经掌握了 `@qiaopeng/tanstack-query-plus` 的所有核心功能:
3894
-
3895
- 1. ✅ 配置 Provider 和最佳实践
3896
- 2. ✅ 基础查询和增强查询
3897
- 3. ✅ Query Key 管理
3898
- 4. ✅ 数据变更和乐观更新
3899
- 5. ✅ 无限滚动和分页
3900
- 6. ✅ 批量查询和仪表盘
3901
- 7. ✅ 智能预取策略
3902
- 8. ✅ Suspense 模式
3903
- 9. ✅ 离线支持和持久化
3904
- 10. ✅ 数据防护与安全
3905
- 11. ✅ 焦点管理
3906
- 12. ✅ 工具函数和选择器
3907
-
3908
- ### 下一步
3909
-
3910
- - 查看 [GitHub 仓库](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus) 获取最新更新
3911
- - 阅读 [TanStack Query 官方文档](https://tanstack.com/query/latest) 了解更多底层概念
3912
- - 在 [Issues](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus/issues) 中提问或反馈
3913
-
3914
- 祝你编码愉快!🚀
3915
3950
  ### 16.9 类型与错误处理规范
3916
3951
 
3917
3952
  - 明确类型参数:在增强 hooks 中显式标注 `TData` 与 `TError`,避免 `any` 漏出
@@ -3979,13 +4014,13 @@ useEnhancedQuery({
3979
4014
  - 数据防护:`useDataGuardQueryConfig`、`useDataGuardMutation`
3980
4015
 
3981
4016
  - `@qiaopeng/tanstack-query-plus/features`
3982
- - 离线:`setupOnlineManager`、`isOnline`、`createOfflineQueueManager`、`OfflineQueueManager`、`mutationRegistry`、`subscribeToOnlineStatus`
4017
+ - 离线:`setupOnlineManager`、`isOnline`、`createOfflineQueueManager`、`OfflineQueueManager`、`mutationRegistry`、`serializeMutationKey`、`subscribeToOnlineStatus`
3983
4018
  - 持久化:`createPersistOptions`、`createPersister`、`clearCache`、`clearExpiredCache`、`checkStorageSize`、`getStorageStats`、`migrateToIndexedDB`
3984
4019
 
3985
4020
  - `@qiaopeng/tanstack-query-plus/components`
3986
4021
  - Loading:`DefaultLoadingFallback`、`FullScreenLoading`、`ListSkeletonFallback`、`PageSkeletonFallback`、`SmallLoadingIndicator`、`TextSkeletonFallback`
3987
4022
  - 错误边界:`QueryErrorBoundary`
3988
- - Suspense:`SuspenseWrapper`、`QuerySuspenseWrapper`
4023
+ - Suspense & SSR:`SuspenseWrapper`、`QuerySuspenseWrapper`、`HydrationBoundary`
3989
4024
 
3990
4025
  - `@qiaopeng/tanstack-query-plus/utils`
3991
4026
  - 选择器:`selectById`、`selectFields`、`compose` 等
@@ -3999,3 +4034,28 @@ useEnhancedQuery({
3999
4034
  - 原生 API 再导出:`useQuery`、`useMutation`、`useInfiniteQuery`、`useSuspenseQuery` 等(src/react-query/index.ts:1)
4000
4035
 
4001
4036
  提示:完整导出列表可在 `package.json:33` 的 `exports` 字段中查看;顶层入口再导出常用原生 API,子路径按模块分层导出,便于 tree-shaking。
4037
+
4038
+ ---
4039
+
4040
+ ## 总结
4041
+
4042
+ 你已经覆盖了 `@qiaopeng/tanstack-query-plus` 的核心能力:
4043
+
4044
+ 1. ✅ 配置 Provider 和最佳实践
4045
+ 2. ✅ 基础查询和增强查询
4046
+ 3. ✅ Query Key 管理
4047
+ 4. ✅ 数据变更和乐观更新
4048
+ 5. ✅ 无限滚动和分页
4049
+ 6. ✅ 批量查询和仪表盘
4050
+ 7. ✅ 智能预取策略
4051
+ 8. ✅ Suspense 模式
4052
+ 9. ✅ 离线支持和持久化
4053
+ 10. ✅ 数据防护与安全
4054
+ 11. ✅ 焦点管理
4055
+ 12. ✅ 工具函数和选择器
4056
+
4057
+ ### 下一步
4058
+
4059
+ - 查看 [GitHub 仓库](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus) 获取最新更新
4060
+ - 阅读 [TanStack Query 官方文档](https://tanstack.com/query/latest) 了解更多底层概念
4061
+ - 在 [Issues](https://github.com/qiaopengg/qiaopeng-tanstack-query-plus/issues) 中提问或反馈
@@ -1,41 +1,39 @@
1
- import type { QueryClient } from "@tanstack/react-query";
2
- import type { PersistedClient, Persister } from "@tanstack/react-query-persist-client";
3
- export declare enum StorageType {
1
+ declare enum StorageType {
4
2
  LOCAL = "localStorage",
5
3
  SESSION = "sessionStorage",
6
4
  INDEXED_DB = "indexedDB",
7
5
  CUSTOM = "custom"
8
6
  }
9
- export declare enum ConnectionQuality {
7
+ declare enum ConnectionQuality {
10
8
  SLOW = "slow",
11
9
  FAST = "fast",
12
10
  UNKNOWN = "unknown"
13
11
  }
14
- export declare enum CachePriority {
12
+ declare enum CachePriority {
15
13
  HIGH = "high",
16
14
  MEDIUM = "medium",
17
15
  LOW = "low"
18
16
  }
19
- export declare enum PersistenceStrategyType {
17
+ declare enum PersistenceStrategyType {
20
18
  AGGRESSIVE = "aggressive",
21
19
  CONSERVATIVE = "conservative",
22
20
  SELECTIVE = "selective",
23
21
  CUSTOM = "custom"
24
22
  }
25
- export interface OperationResult<T = unknown> {
23
+ interface OperationResult<T = unknown> {
26
24
  success: boolean;
27
25
  data?: T;
28
26
  error?: Error;
29
27
  duration?: number;
30
28
  metadata?: Record<string, unknown>;
31
29
  }
32
- export interface NetworkInformation {
30
+ interface NetworkInformation {
33
31
  effectiveType?: "4g" | "3g" | "2g" | "slow-2g";
34
32
  saveData?: boolean;
35
33
  downlink?: number;
36
34
  rtt?: number;
37
35
  }
38
- export interface NetworkStatus {
36
+ interface NetworkStatus {
39
37
  isOnline: boolean;
40
38
  isOffline: boolean;
41
39
  connectionQuality: ConnectionQuality;
@@ -43,12 +41,12 @@ export interface NetworkStatus {
43
41
  lastOnlineAt?: Date;
44
42
  lastOfflineAt?: Date;
45
43
  }
46
- export type DeepReadonly<T> = {
44
+ type DeepReadonly<T> = {
47
45
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
48
46
  };
49
- export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
50
- export type Required<T, K extends keyof T> = T & {
47
+ type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
48
+ type Required<T, K extends keyof T> = T & {
51
49
  [P in K]-?: T[P];
52
50
  };
53
- export type { PersistedClient, Persister, QueryClient };
54
- //# sourceMappingURL=base.d.ts.map
51
+
52
+ export { ConnectionQuality as C, type DeepReadonly as D, type NetworkInformation as N, type OperationResult as O, PersistenceStrategyType as P, type Required as R, StorageType as S, CachePriority as a, type NetworkStatus as b, type Optional as c };
@@ -0,0 +1,52 @@
1
+ declare enum StorageType {
2
+ LOCAL = "localStorage",
3
+ SESSION = "sessionStorage",
4
+ INDEXED_DB = "indexedDB",
5
+ CUSTOM = "custom"
6
+ }
7
+ declare enum ConnectionQuality {
8
+ SLOW = "slow",
9
+ FAST = "fast",
10
+ UNKNOWN = "unknown"
11
+ }
12
+ declare enum CachePriority {
13
+ HIGH = "high",
14
+ MEDIUM = "medium",
15
+ LOW = "low"
16
+ }
17
+ declare enum PersistenceStrategyType {
18
+ AGGRESSIVE = "aggressive",
19
+ CONSERVATIVE = "conservative",
20
+ SELECTIVE = "selective",
21
+ CUSTOM = "custom"
22
+ }
23
+ interface OperationResult<T = unknown> {
24
+ success: boolean;
25
+ data?: T;
26
+ error?: Error;
27
+ duration?: number;
28
+ metadata?: Record<string, unknown>;
29
+ }
30
+ interface NetworkInformation {
31
+ effectiveType?: "4g" | "3g" | "2g" | "slow-2g";
32
+ saveData?: boolean;
33
+ downlink?: number;
34
+ rtt?: number;
35
+ }
36
+ interface NetworkStatus {
37
+ isOnline: boolean;
38
+ isOffline: boolean;
39
+ connectionQuality: ConnectionQuality;
40
+ connection?: NetworkInformation;
41
+ lastOnlineAt?: Date;
42
+ lastOfflineAt?: Date;
43
+ }
44
+ type DeepReadonly<T> = {
45
+ readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
46
+ };
47
+ type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
48
+ type Required<T, K extends keyof T> = T & {
49
+ [P in K]-?: T[P];
50
+ };
51
+
52
+ export { ConnectionQuality as C, type DeepReadonly as D, type NetworkInformation as N, type OperationResult as O, PersistenceStrategyType as P, type Required as R, StorageType as S, CachePriority as a, type NetworkStatus as b, type Optional as c };