@hitch42/applet 0.1.0-beta.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.
- package/LICENSE +21 -0
- package/dist/_internal/client.d.ts +7 -0
- package/dist/_internal/client.js +169 -0
- package/dist/_internal/server.d.ts +92 -0
- package/dist/_internal/server.js +181 -0
- package/dist/applet.d.ts +1 -0
- package/dist/applet.js +184 -0
- package/dist/batch-Qa4B4-Yp.d.ts +30 -0
- package/dist/build-BlmLiKro.js +90 -0
- package/dist/build-CcT-wNN9.js +2 -0
- package/dist/ci-0Q2mUh53.js +68 -0
- package/dist/client.d.ts +48 -0
- package/dist/client.js +38 -0
- package/dist/contract-QUvEGiRI.d.ts +23 -0
- package/dist/deploy-BbL3GObV.js +2579 -0
- package/dist/email-DBTVhNB_.js +62 -0
- package/dist/generate-XB-72Fzj.js +537 -0
- package/dist/generate-wIN3IYqL.js +2 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +251 -0
- package/dist/init-DwsXRUk-.js +244 -0
- package/dist/lazy-client-x0DCI98S.js +64 -0
- package/dist/load-config-OKZU3UKn.js +27 -0
- package/dist/login-BBO74hPC.js +12 -0
- package/dist/logs-XvK6Zs5Y.js +183 -0
- package/dist/manifest-4ZAc6HUk.js +191 -0
- package/dist/manifest-I-9s8R36.d.ts +88 -0
- package/dist/me-BW7Paary.js +32 -0
- package/dist/project-B0qNXnFu.js +536 -0
- package/dist/prompt-ChS-grYO.js +29 -0
- package/dist/query-cache-CXmAyLv3.js +82 -0
- package/dist/react.d.ts +37 -0
- package/dist/react.js +515 -0
- package/dist/schedules-BkWZsbSs.js +42 -0
- package/dist/server.d.ts +46 -0
- package/dist/server.js +104 -0
- package/dist/telephony-protocol-D-nf3Gca.d.ts +76 -0
- package/dist/telephony.d.ts +77 -0
- package/dist/telephony.js +607 -0
- package/dist/upload-DKZzz5kW.d.ts +112 -0
- package/dist/upload-DRbVhuDm.js +114 -0
- package/dist/variables-0tjnAeut.js +108 -0
- package/dist/vite.d.ts +63 -0
- package/dist/vite.js +816 -0
- package/dist/workflow-CTo2kZF1.js +51 -0
- package/dist/workflow-DurM6Fwx.d.ts +28 -0
- package/dist/workflow-engine-MogejNfF.js +117 -0
- package/dist/workspace-DruAZPmV.js +390 -0
- package/package.json +112 -0
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +163 -0
- package/scaffold/.agents/skills/hitch-applets/references/client.md +73 -0
- package/scaffold/.agents/skills/hitch-applets/references/email-tracking.md +49 -0
- package/scaffold/.agents/skills/hitch-applets/references/files.md +109 -0
- package/scaffold/.agents/skills/hitch-applets/references/manifest.md +198 -0
- package/scaffold/.agents/skills/hitch-applets/references/markdown.md +37 -0
- package/scaffold/.agents/skills/hitch-applets/references/performance.md +74 -0
- package/scaffold/.agents/skills/hitch-applets/references/records.md +176 -0
- package/scaffold/.agents/skills/hitch-applets/references/schedules.md +91 -0
- package/scaffold/.agents/skills/hitch-applets/references/server.md +95 -0
- package/scaffold/.agents/skills/hitch-applets/references/workflows.md +81 -0
- package/scaffold/.agents/skills/hitch-cli/SKILL.md +129 -0
- package/scaffold/.agents/skills/hitch-data/SKILL.md +52 -0
- package/scaffold/.agents/skills/hitch-data/references/attributes.md +127 -0
- package/scaffold/.agents/skills/hitch-data/references/limits.md +64 -0
- package/scaffold/.agents/skills/hitch-theory/SKILL.md +151 -0
- package/scaffold/.agents/skills/react-best-practices/SKILL.md +127 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-effect-event-deps.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/scaffold/.agents/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-defer-await.md +82 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-dependencies.md +48 -0
- package/scaffold/.agents/skills/react-best-practices/rules/async-parallel.md +24 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-analyzable-paths.md +42 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-conditional.md +35 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +46 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/bundle-preload.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-event-listeners.md +78 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-localstorage-schema.md +74 -0
- package/scaffold/.agents/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +110 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-function-results.md +58 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-cache-storage.md +56 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-flatmap-filter.md +51 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-length-check-first.md +50 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-request-idle-callback.md +104 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/scaffold/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +32 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-resource-hints.md +81 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-script-defer-async.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rendering-usetransition-loading.md +43 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +77 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +56 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo-with-default-value.md +36 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-no-inline-components.md +75 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/scaffold/.agents/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/scaffold/.agents/skills/tanstack-query/SKILL.md +136 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/automatic-invalidation-after-mutations.md +124 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/broadcast-realtime-and-multi-tab-synchronization.md +150 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/compose-query-with-tanstack-router-and-start.md +248 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/enforce-query-best-practices-with-eslint.md +167 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/persist-offline-and-restore-caches.md +181 -0
- package/scaffold/.agents/skills/tanstack-query/references/compositions/query-data-and-forms.md +156 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/build-query-abstractions.md +130 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/cancel-queries-and-consume-abort-signals.md +176 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/concurrent-optimistic-updates.md +135 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/coordinate-query-execution.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md +182 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/fetch-and-observe-queries.md +193 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/implement-optimistic-updates-and-cache-writes.md +168 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/paginate-and-build-infinite-queries.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/seed-placeholder-select-and-transform-data.md +188 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/selectors-and-derived-state.md +145 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/tune-defaults-freshness-retries-and-refetching.md +172 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/understand-query-internals-and-observers.md +104 -0
- package/scaffold/.agents/skills/tanstack-query/references/core/write-mutations-and-invalidate-related-queries.md +183 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/debug-with-devtools.md +169 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/handle-status-and-errors.md +119 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/shape-data-and-render-efficiently.md +184 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/use-framework-adapter-reactivity.md +185 -0
- package/scaffold/.agents/skills/tanstack-query/references/framework/use-suspense-and-error-boundaries.md +208 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/migrate-major-versions-and-codemods.md +169 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/prefetch-and-remove-request-waterfalls.md +228 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/setup-query-client-and-providers.md +161 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/ssr-hydration-and-streaming.md +209 -0
- package/scaffold/.agents/skills/tanstack-query/references/lifecycle/test-query-code.md +160 -0
- package/scaffold/.agents/skills/tanstack-router/SKILL.md +134 -0
- package/scaffold/.agents/skills/tanstack-router/references/compositions/router-query.md +412 -0
- package/scaffold/.agents/skills/tanstack-router/references/react-router.md +495 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/auth-and-guards.md +495 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/code-splitting.md +318 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/data-loading.md +490 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/index.md +158 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/navigation.md +433 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/not-found-and-errors.md +436 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/path-params.md +383 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/search-params.md +343 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/ssr.md +462 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-core/type-safety.md +493 -0
- package/scaffold/.agents/skills/tanstack-router/references/router-plugin.md +250 -0
- package/scaffold/.agents/skills/tanstack-router/references/virtual-file-routes.md +215 -0
- package/scaffold/.agents/skills/web-design-guidelines/SKILL.md +184 -0
- package/scaffold/.github/workflows/hitch.yml +15 -0
- package/scaffold/AGENTS.md +38 -0
- package/scaffold/applet/components.json +25 -0
- package/scaffold/applet/src/client/components/ui/alert.tsx +73 -0
- package/scaffold/applet/src/client/components/ui/avatar.tsx +100 -0
- package/scaffold/applet/src/client/components/ui/badge.tsx +55 -0
- package/scaffold/applet/src/client/components/ui/button.tsx +90 -0
- package/scaffold/applet/src/client/components/ui/card.tsx +85 -0
- package/scaffold/applet/src/client/components/ui/checkbox.tsx +35 -0
- package/scaffold/applet/src/client/components/ui/dialog.tsx +164 -0
- package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +235 -0
- package/scaffold/applet/src/client/components/ui/input-group.tsx +144 -0
- package/scaffold/applet/src/client/components/ui/input.tsx +22 -0
- package/scaffold/applet/src/client/components/ui/label.tsx +29 -0
- package/scaffold/applet/src/client/components/ui/popover.tsx +74 -0
- package/scaffold/applet/src/client/components/ui/select.tsx +243 -0
- package/scaffold/applet/src/client/components/ui/separator.tsx +25 -0
- package/scaffold/applet/src/client/components/ui/sheet.tsx +177 -0
- package/scaffold/applet/src/client/components/ui/skeleton.tsx +13 -0
- package/scaffold/applet/src/client/components/ui/spinner.tsx +17 -0
- package/scaffold/applet/src/client/components/ui/switch.tsx +41 -0
- package/scaffold/applet/src/client/components/ui/table.tsx +114 -0
- package/scaffold/applet/src/client/components/ui/tabs.tsx +78 -0
- package/scaffold/applet/src/client/components/ui/textarea.tsx +23 -0
- package/scaffold/applet/src/client/lib/utils.ts +1 -0
- package/scaffold/applet/src/client/styles/globals.css +136 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core/coordinate-query-execution
|
|
3
|
+
description: >
|
|
4
|
+
Use this when coordinating enabled, skipToken, dependent queries, useQueries,
|
|
5
|
+
parallel queries, disabled queries, background fetching indicators, isFetching,
|
|
6
|
+
fetchStatus, and declarative refetch behavior.
|
|
7
|
+
type: core
|
|
8
|
+
library: TanStack Query
|
|
9
|
+
library_version: "5.101.0"
|
|
10
|
+
requires:
|
|
11
|
+
- core/fetch-and-observe-queries
|
|
12
|
+
- core/tune-defaults-freshness-retries-and-refetching
|
|
13
|
+
sources:
|
|
14
|
+
- TanStack/query:docs/framework/react/guides/dependent-queries.md
|
|
15
|
+
- TanStack/query:docs/framework/react/guides/parallel-queries.md
|
|
16
|
+
- TanStack/query:docs/framework/react/guides/disabling-queries.md
|
|
17
|
+
- TanStack/query:docs/framework/react/guides/background-fetching-indicators.md
|
|
18
|
+
- TanStack/query:docs/framework/react/reference/useQueries.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { useQuery } from "@tanstack/react-query";
|
|
25
|
+
|
|
26
|
+
export function Projects(props: { userId?: string }) {
|
|
27
|
+
const projects = useQuery({
|
|
28
|
+
queryKey: ["projects", props.userId],
|
|
29
|
+
queryFn: async () => [{ id: "p1", userId: props.userId }],
|
|
30
|
+
enabled: Boolean(props.userId),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return <pre>{JSON.stringify(projects.data ?? [])}</pre>;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Core Patterns
|
|
38
|
+
|
|
39
|
+
### Gate by dependency
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { useQuery } from "@tanstack/react-query";
|
|
43
|
+
|
|
44
|
+
export function useUserProjects(userId: string | undefined) {
|
|
45
|
+
return useQuery({
|
|
46
|
+
queryKey: ["projects", userId],
|
|
47
|
+
queryFn: async () => [{ id: "p1", userId }],
|
|
48
|
+
enabled: userId !== undefined,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Run dynamic parallel queries
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { useQueries } from "@tanstack/react-query";
|
|
57
|
+
|
|
58
|
+
export function useMessages(ids: Array<string>) {
|
|
59
|
+
return useQueries({
|
|
60
|
+
queries: ids.map((id) => ({
|
|
61
|
+
queryKey: ["message", id],
|
|
62
|
+
queryFn: async () => ({ id, text: "Hello" }),
|
|
63
|
+
})),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Show background refresh separately
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { useIsFetching } from "@tanstack/react-query";
|
|
72
|
+
|
|
73
|
+
export function GlobalRefreshIndicator() {
|
|
74
|
+
const count = useIsFetching();
|
|
75
|
+
return count > 0 ? <p>Refreshing</p> : null;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Common Mistakes
|
|
80
|
+
|
|
81
|
+
### HIGH Imperative disabled query
|
|
82
|
+
|
|
83
|
+
Wrong:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { useQuery } from "@tanstack/react-query";
|
|
87
|
+
|
|
88
|
+
export function useSearch(term: string) {
|
|
89
|
+
return useQuery({
|
|
90
|
+
queryKey: ["search"],
|
|
91
|
+
queryFn: async () => [term],
|
|
92
|
+
enabled: false,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Correct:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { useQuery } from "@tanstack/react-query";
|
|
101
|
+
|
|
102
|
+
export function useSearch(term: string) {
|
|
103
|
+
return useQuery({
|
|
104
|
+
queryKey: ["search", term],
|
|
105
|
+
queryFn: async () => [term],
|
|
106
|
+
enabled: term.length > 0,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Permanent disabling opts out of normal invalidation and dependency-driven cache behavior.
|
|
112
|
+
|
|
113
|
+
Source: TanStack/query:docs/framework/react/guides/disabling-queries.md
|
|
114
|
+
|
|
115
|
+
### HIGH Duplicate useQueries keys
|
|
116
|
+
|
|
117
|
+
Wrong:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { useQueries } from "@tanstack/react-query";
|
|
121
|
+
|
|
122
|
+
export function useUsers(ids: Array<string>) {
|
|
123
|
+
return useQueries({
|
|
124
|
+
queries: ids.map((id) => ({
|
|
125
|
+
queryKey: ["user"],
|
|
126
|
+
queryFn: async () => ({ id }),
|
|
127
|
+
})),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Correct:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { useQueries } from "@tanstack/react-query";
|
|
136
|
+
|
|
137
|
+
export function useUsers(ids: Array<string>) {
|
|
138
|
+
return useQueries({
|
|
139
|
+
queries: ids.map((id) => ({
|
|
140
|
+
queryKey: ["user", id],
|
|
141
|
+
queryFn: async () => ({ id }),
|
|
142
|
+
})),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Duplicate keys can share placeholder, selected, or cached data between different items.
|
|
148
|
+
|
|
149
|
+
Source: TanStack/query:docs/framework/react/reference/useQueries.md
|
|
150
|
+
|
|
151
|
+
### MEDIUM Full-page spinner on background refetch
|
|
152
|
+
|
|
153
|
+
Wrong:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { useQuery } from "@tanstack/react-query";
|
|
157
|
+
|
|
158
|
+
export function Todos() {
|
|
159
|
+
const query = useQuery({
|
|
160
|
+
queryKey: ["todos"],
|
|
161
|
+
queryFn: async () => [{ id: 1 }],
|
|
162
|
+
});
|
|
163
|
+
return query.isFetching ? <p>Loading</p> : <pre>{JSON.stringify(query.data)}</pre>;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Correct:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { useQuery } from "@tanstack/react-query";
|
|
171
|
+
|
|
172
|
+
export function Todos() {
|
|
173
|
+
const query = useQuery({
|
|
174
|
+
queryKey: ["todos"],
|
|
175
|
+
queryFn: async () => [{ id: 1 }],
|
|
176
|
+
});
|
|
177
|
+
return (
|
|
178
|
+
<pre>
|
|
179
|
+
{query.isFetching ? "Refreshing " : ""}
|
|
180
|
+
{JSON.stringify(query.data ?? [])}
|
|
181
|
+
</pre>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`isFetching` also covers background refreshes after data is already available.
|
|
187
|
+
|
|
188
|
+
Source: TanStack/query:docs/framework/react/guides/background-fetching-indicators.md
|
package/scaffold/.agents/skills/tanstack-query/references/core/design-query-keys-and-options.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core/design-query-keys-and-options
|
|
3
|
+
description: >
|
|
4
|
+
Use this when designing queryKey arrays, queryFn inputs, queryOptions,
|
|
5
|
+
infiniteQueryOptions, mutationOptions, skipToken, key factories, or TypeScript
|
|
6
|
+
inference for TanStack Query reads and writes.
|
|
7
|
+
type: core
|
|
8
|
+
library: TanStack Query
|
|
9
|
+
library_version: "5.101.0"
|
|
10
|
+
sources:
|
|
11
|
+
- TanStack/query:docs/framework/react/guides/query-keys.md
|
|
12
|
+
- TanStack/query:docs/framework/react/guides/query-options.md
|
|
13
|
+
- TanStack/query:docs/framework/react/typescript.md
|
|
14
|
+
- TanStack/query:docs/eslint/exhaustive-deps.md
|
|
15
|
+
- TanStack/query:docs/eslint/prefer-query-options.md
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { queryOptions } from "@tanstack/react-query";
|
|
22
|
+
|
|
23
|
+
export function todoOptions(todoId: string) {
|
|
24
|
+
return queryOptions({
|
|
25
|
+
queryKey: ["todo", todoId],
|
|
26
|
+
queryFn: async () => ({ id: todoId, title: "Ship skills" }),
|
|
27
|
+
staleTime: 60_000,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Core Patterns
|
|
33
|
+
|
|
34
|
+
### Put every query variable in the key
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { queryOptions } from "@tanstack/react-query";
|
|
38
|
+
|
|
39
|
+
export function projectsOptions(teamId: string, page: number) {
|
|
40
|
+
return queryOptions({
|
|
41
|
+
queryKey: ["projects", teamId, page],
|
|
42
|
+
queryFn: async () => ({ teamId, page, items: [] as Array<{ id: string }> }),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Share one options factory
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { QueryClient, useQuery, queryOptions } from "@tanstack/react-query";
|
|
51
|
+
|
|
52
|
+
export const queryClient = new QueryClient();
|
|
53
|
+
|
|
54
|
+
export function userOptions(userId: string) {
|
|
55
|
+
return queryOptions({
|
|
56
|
+
queryKey: ["user", userId],
|
|
57
|
+
queryFn: async () => ({ id: userId, name: "Tanner" }),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function useUser(userId: string) {
|
|
62
|
+
return useQuery(userOptions(userId));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function preloadUser(userId: string) {
|
|
66
|
+
return queryClient.ensureQueryData(userOptions(userId));
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Use skipToken for typesafe absence
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { skipToken, useQuery } from "@tanstack/react-query";
|
|
74
|
+
|
|
75
|
+
export function useMaybeTodo(todoId: string | undefined) {
|
|
76
|
+
return useQuery({
|
|
77
|
+
queryKey: ["todo", todoId],
|
|
78
|
+
queryFn: todoId ? async () => ({ id: todoId }) : skipToken,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Common Mistakes
|
|
84
|
+
|
|
85
|
+
### CRITICAL Missing variable in key
|
|
86
|
+
|
|
87
|
+
Wrong:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { useQuery } from "@tanstack/react-query";
|
|
91
|
+
|
|
92
|
+
export function useProject(teamId: string) {
|
|
93
|
+
return useQuery({
|
|
94
|
+
queryKey: ["project"],
|
|
95
|
+
queryFn: async () => ({ teamId }),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Correct:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { useQuery } from "@tanstack/react-query";
|
|
104
|
+
|
|
105
|
+
export function useProject(teamId: string) {
|
|
106
|
+
return useQuery({
|
|
107
|
+
queryKey: ["project", teamId],
|
|
108
|
+
queryFn: async () => ({ teamId }),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Query keys define cache identity; missing variables merge distinct data.
|
|
114
|
+
|
|
115
|
+
Source: TanStack/query:docs/framework/react/guides/query-keys.md
|
|
116
|
+
|
|
117
|
+
### HIGH Key and queryFn drift
|
|
118
|
+
|
|
119
|
+
Wrong:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { useQuery } from "@tanstack/react-query";
|
|
123
|
+
|
|
124
|
+
export function useTodo(todoId: string) {
|
|
125
|
+
return useQuery({ queryKey: ["todo"], queryFn: async () => ({ id: todoId }) });
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Correct:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import { queryOptions, useQuery } from "@tanstack/react-query";
|
|
133
|
+
|
|
134
|
+
function todoOptions(todoId: string) {
|
|
135
|
+
return queryOptions({
|
|
136
|
+
queryKey: ["todo", todoId],
|
|
137
|
+
queryFn: async () => ({ id: todoId }),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function useTodo(todoId: string) {
|
|
142
|
+
return useQuery(todoOptions(todoId));
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Options factories keep identity, fetch behavior, and inference together across hooks and prefetches.
|
|
147
|
+
|
|
148
|
+
Source: TanStack/query:docs/eslint/prefer-query-options.md
|
|
149
|
+
|
|
150
|
+
### HIGH skipToken inside suspense query
|
|
151
|
+
|
|
152
|
+
Wrong:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { skipToken, useSuspenseQuery } from "@tanstack/react-query";
|
|
156
|
+
|
|
157
|
+
export function useTodo(todoId: string | undefined) {
|
|
158
|
+
return useSuspenseQuery({
|
|
159
|
+
queryKey: ["todo", todoId],
|
|
160
|
+
queryFn: todoId ? async () => ({ id: todoId }) : skipToken,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Correct:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { skipToken, useQuery } from "@tanstack/react-query";
|
|
169
|
+
|
|
170
|
+
export function useTodo(todoId: string | undefined) {
|
|
171
|
+
return useQuery({
|
|
172
|
+
queryKey: ["todo", todoId],
|
|
173
|
+
queryFn: todoId ? async () => ({ id: todoId }) : skipToken,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Suspense queries require a guaranteed query function and cannot be conditionally disabled.
|
|
179
|
+
|
|
180
|
+
Source: TanStack/query:docs/framework/react/guides/suspense.md
|
|
181
|
+
|
|
182
|
+
See also: `compositions/enforce-query-best-practices-with-eslint` for rules that enforce key and options mistakes.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: core/fetch-and-observe-queries
|
|
3
|
+
description: >
|
|
4
|
+
Use this when reading server state with useQuery, useQueries, createQuery,
|
|
5
|
+
injectQuery, QueryObserver, QueryClient.fetchQuery, ensureQueryData, status,
|
|
6
|
+
fetchStatus, pending, paused, success, and error states.
|
|
7
|
+
type: core
|
|
8
|
+
library: TanStack Query
|
|
9
|
+
library_version: "5.101.0"
|
|
10
|
+
requires:
|
|
11
|
+
- lifecycle/setup-query-client-and-providers
|
|
12
|
+
- core/design-query-keys-and-options
|
|
13
|
+
sources:
|
|
14
|
+
- TanStack/query:docs/framework/react/guides/queries.md
|
|
15
|
+
- TanStack/query:docs/framework/react/guides/query-functions.md
|
|
16
|
+
- TanStack/query:docs/reference/QueryObserver.md
|
|
17
|
+
- TanStack/query:docs/reference/QueryClient.md
|
|
18
|
+
- TanStack/query:docs/eslint/no-void-query-fn.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { useQuery } from "@tanstack/react-query";
|
|
25
|
+
|
|
26
|
+
export function Todos() {
|
|
27
|
+
const query = useQuery({
|
|
28
|
+
queryKey: ["todos"],
|
|
29
|
+
queryFn: async () => [{ id: 1, title: "Ship" }],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (query.isPending) return <p>Loading</p>;
|
|
33
|
+
if (query.isError) return <p>{query.error.message}</p>;
|
|
34
|
+
return <pre>{JSON.stringify(query.data)}</pre>;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Core Patterns
|
|
39
|
+
|
|
40
|
+
### Fetch imperatively through QueryClient
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
44
|
+
|
|
45
|
+
const queryClient = new QueryClient();
|
|
46
|
+
|
|
47
|
+
export function loadTodo(todoId: string) {
|
|
48
|
+
return queryClient.fetchQuery({
|
|
49
|
+
queryKey: ["todo", todoId],
|
|
50
|
+
queryFn: async () => ({ id: todoId }),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Ensure cached data for loaders
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
59
|
+
|
|
60
|
+
const queryClient = new QueryClient();
|
|
61
|
+
|
|
62
|
+
export function ensureTodos() {
|
|
63
|
+
return queryClient.ensureQueryData({
|
|
64
|
+
queryKey: ["todos"],
|
|
65
|
+
queryFn: async () => [{ id: 1 }],
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Distinguish status from fetchStatus
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { useQuery } from "@tanstack/react-query";
|
|
74
|
+
|
|
75
|
+
export function TodoCount() {
|
|
76
|
+
const query = useQuery({
|
|
77
|
+
queryKey: ["todos"],
|
|
78
|
+
queryFn: async () => [{ id: 1 }],
|
|
79
|
+
});
|
|
80
|
+
const label =
|
|
81
|
+
query.fetchStatus === "fetching" && query.status === "success" ? "Refreshing" : "Ready";
|
|
82
|
+
return (
|
|
83
|
+
<p>
|
|
84
|
+
{query.data?.length ?? 0} {label}
|
|
85
|
+
</p>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Common Mistakes
|
|
91
|
+
|
|
92
|
+
### CRITICAL Void query function
|
|
93
|
+
|
|
94
|
+
Wrong:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { useQuery } from "@tanstack/react-query";
|
|
98
|
+
|
|
99
|
+
export function useTodos() {
|
|
100
|
+
return useQuery({
|
|
101
|
+
queryKey: ["todos"],
|
|
102
|
+
queryFn: async () => {
|
|
103
|
+
await Promise.resolve([{ id: 1 }]);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Correct:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { useQuery } from "@tanstack/react-query";
|
|
113
|
+
|
|
114
|
+
export function useTodos() {
|
|
115
|
+
return useQuery({
|
|
116
|
+
queryKey: ["todos"],
|
|
117
|
+
queryFn: async () => Promise.resolve([{ id: 1 }]),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Query functions must return data; a missing return caches `undefined`.
|
|
123
|
+
|
|
124
|
+
Source: TanStack/query:docs/eslint/no-void-query-fn.md
|
|
125
|
+
|
|
126
|
+
### HIGH Only checking pending offline
|
|
127
|
+
|
|
128
|
+
Wrong:
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
import { useQuery } from "@tanstack/react-query";
|
|
132
|
+
|
|
133
|
+
export function Todos() {
|
|
134
|
+
const query = useQuery({
|
|
135
|
+
queryKey: ["todos"],
|
|
136
|
+
queryFn: async () => [{ id: 1 }],
|
|
137
|
+
networkMode: "online",
|
|
138
|
+
});
|
|
139
|
+
return query.isPending ? <p>Loading</p> : <p>{query.fetchStatus}</p>;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Correct:
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
import { useQuery } from "@tanstack/react-query";
|
|
147
|
+
|
|
148
|
+
export function Todos() {
|
|
149
|
+
const query = useQuery({
|
|
150
|
+
queryKey: ["todos"],
|
|
151
|
+
queryFn: async () => [{ id: 1 }],
|
|
152
|
+
networkMode: "online",
|
|
153
|
+
});
|
|
154
|
+
return query.fetchStatus === "paused" ? <p>Offline</p> : <p>{query.status}</p>;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`status` describes data state; `fetchStatus` describes whether fetching is paused, fetching, or idle.
|
|
159
|
+
|
|
160
|
+
Source: TanStack/query:docs/framework/react/guides/queries.md
|
|
161
|
+
|
|
162
|
+
### HIGH Using queries for writes
|
|
163
|
+
|
|
164
|
+
Wrong:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { useQuery } from "@tanstack/react-query";
|
|
168
|
+
|
|
169
|
+
export function useSaveTodo(title: string) {
|
|
170
|
+
return useQuery({
|
|
171
|
+
queryKey: ["saveTodo", title],
|
|
172
|
+
queryFn: async () => ({ id: 1, title }),
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Correct:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { useMutation } from "@tanstack/react-query";
|
|
181
|
+
|
|
182
|
+
export function useSaveTodo() {
|
|
183
|
+
return useMutation({
|
|
184
|
+
mutationFn: async (title: string) => ({ id: 1, title }),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Queries are for reads; writes need mutation lifecycle hooks, invalidation, rollback, and mutation state.
|
|
190
|
+
|
|
191
|
+
Source: TanStack/query:docs/framework/react/guides/mutations.md
|
|
192
|
+
|
|
193
|
+
See also: `core/tune-defaults-freshness-retries-and-refetching` for how defaults change status behavior.
|