@punks/cli 0.1.16 → 1.0.0
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/AGENTS.md +10 -0
- package/README.md +64 -0
- package/dist/data/AGENTS.md +123 -0
- package/dist/data/catalog/lint.ts +349 -0
- package/dist/data/catalog/packs.ts +44 -0
- package/dist/data/catalog/skills.ts +47 -0
- package/dist/data/catalog/tools.ts +22 -0
- package/dist/data/hooks/format-edited-file.mjs +554 -0
- package/dist/data/hooks/format-edited-file.py +157 -0
- package/dist/data/hooks/format-edited-file.sh +37 -0
- package/dist/data/hooks/require-tests-for-pr.mjs +144 -0
- package/dist/data/scripts/sync-subagents.mjs +420 -0
- package/dist/data/subagents/manifest.mjs +253 -0
- package/dist/index.js +46415 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/SKILL.md +50 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/backend/backend-domain-structure/references/layout.md +167 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/SKILL.md +49 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/references/strategy-matrix.md +34 -0
- package/dist/skills/agnostic/backend/backend-recoverable-actions/references/test-matrix.md +34 -0
- package/dist/skills/agnostic/docs/docs-maintenance/SKILL.md +193 -0
- package/dist/skills/agnostic/docs/docs-maintenance/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/docs/docs-maintenance/references/concept-pages.md +48 -0
- package/dist/skills/agnostic/docs/docs-maintenance/references/flow-pages.md +41 -0
- package/dist/skills/agnostic/frontend/agent-browser/.clawdhub/origin.json +7 -0
- package/dist/skills/agnostic/frontend/agent-browser/SKILL.md +229 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/authentication.md +202 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/commands.md +259 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/proxy-support.md +188 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/session-management.md +193 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/snapshot-refs.md +194 -0
- package/dist/skills/agnostic/frontend/agent-browser/references/video-recording.md +173 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/authenticated-session.sh +97 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/capture-workflow.sh +69 -0
- package/dist/skills/agnostic/frontend/agent-browser/templates/form-automation.sh +62 -0
- package/dist/skills/agnostic/frontend/design-taste-frontend/SKILL.md +226 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/SKILL.md +55 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/references/react/structure.md +102 -0
- package/dist/skills/agnostic/frontend/frontend-domain-structure/references/structure.md +257 -0
- package/dist/skills/agnostic/frontend/gpt-taste/SKILL.md +74 -0
- package/dist/skills/agnostic/frontend/image-taste-frontend/SKILL.md +1102 -0
- package/dist/skills/agnostic/frontend/redesign-existing-projects/SKILL.md +178 -0
- package/dist/skills/agnostic/planning/create-plan/REFERENCE.md +37 -0
- package/dist/skills/agnostic/planning/create-plan/SKILL.md +69 -0
- package/dist/skills/agnostic/planning/create-plan/references/backlog-sync.md +44 -0
- package/dist/skills/agnostic/planning/create-plan/references/grill-phase.md +86 -0
- package/dist/skills/agnostic/planning/create-plan/references/plan-schema.md +66 -0
- package/dist/skills/agnostic/planning/create-plan/references/planner-phase.md +39 -0
- package/dist/skills/agnostic/planning/create-plan/references/stop-conditions.md +18 -0
- package/dist/skills/agnostic/planning/create-plan/references/tdd-phase.md +26 -0
- package/dist/skills/agnostic/planning/create-spec/SKILL.md +57 -0
- package/dist/skills/agnostic/planning/create-spec/assets/SPEC-TEMPLATE.md +91 -0
- package/dist/skills/agnostic/planning/create-spec/references/discovery.md +44 -0
- package/dist/skills/agnostic/planning/create-spec/references/folder-naming.md +27 -0
- package/dist/skills/agnostic/planning/create-spec/references/handoff.md +47 -0
- package/dist/skills/agnostic/planning/create-spec/references/questioning.md +41 -0
- package/dist/skills/agnostic/planning/create-spec/references/spec-quality-bar.md +58 -0
- package/dist/skills/agnostic/planning/create-spec/references/wiki-bookkeeping.md +26 -0
- package/dist/skills/agnostic/planning/grill-me/SKILL.md +28 -0
- package/dist/skills/agnostic/planning/implement-spec/SKILL.md +72 -0
- package/dist/skills/agnostic/planning/implement-spec/assets/IMPLEMENTATION-NOTES-TEMPLATE.md +47 -0
- package/dist/skills/agnostic/planning/implement-spec/references/lifecycle.md +149 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel-orchestration.md +102 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel-worker-brief.md +65 -0
- package/dist/skills/agnostic/planning/implement-spec/references/parallel.md +56 -0
- package/dist/skills/agnostic/planning/implement-spec/references/sequential.md +28 -0
- package/dist/skills/agnostic/planning/swarm-planner/SKILL.md +179 -0
- package/dist/skills/agnostic/quality/simplify/SKILL.md +14 -0
- package/dist/skills/agnostic/quality/tdd/SKILL.md +107 -0
- package/dist/skills/agnostic/quality/tdd/deep-modules.md +33 -0
- package/dist/skills/agnostic/quality/tdd/interface-design.md +31 -0
- package/dist/skills/agnostic/quality/tdd/mocking.md +59 -0
- package/dist/skills/agnostic/quality/tdd/refactoring.md +10 -0
- package/dist/skills/agnostic/quality/tdd/tests.md +61 -0
- package/dist/skills/agnostic/requirements/requirements-grill/SKILL.md +42 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/artifact-output.md +73 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/grilling-flow.md +57 -0
- package/dist/skills/agnostic/requirements/requirements-grill/references/wiki-output.md +94 -0
- package/dist/skills/agnostic/requirements/write-backlog/EXAMPLES.md +67 -0
- package/dist/skills/agnostic/requirements/write-backlog/REFERENCE.md +253 -0
- package/dist/skills/agnostic/requirements/write-backlog/SKILL.md +68 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/concepts/backlog-model.md +69 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/concepts/story-shape.md +66 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/azure-devops-create-payload.md +63 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/github-issues-create-payload.md +48 -0
- package/dist/skills/agnostic/requirements/write-backlog/assets/providers/linear-create-payload.md +76 -0
- package/dist/skills/agnostic/research/improve-codebase-architecture/REFERENCE.md +78 -0
- package/dist/skills/agnostic/research/improve-codebase-architecture/SKILL.md +76 -0
- package/dist/skills/agnostic/research/parallel-research/SKILL.md +68 -0
- package/dist/skills/agnostic/research/parallel-research/agents/openai.yaml +4 -0
- package/dist/skills/agnostic/subagents/swarm-planner/SKILL.md +179 -0
- package/dist/skills/agnostic/write-a-skill/SKILL.md +117 -0
- package/dist/skills/frameworks/better-auth/better-auth-best-practices/SKILL.md +166 -0
- package/dist/skills/frameworks/better-auth/better-auth-security-best-practices/SKILL.MD +432 -0
- package/dist/skills/frameworks/effect/effect-authoring/SKILL.md +116 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/branded-types.md +98 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/effect-atom-patterns.md +257 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/effect-primitives.md +144 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/error-patterns.md +156 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/otel-patterns.md +113 -0
- package/dist/skills/frameworks/effect/effect-authoring/references/test-patterns.md +146 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/SKILL.md +96 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/agents/openai.yaml +4 -0
- package/dist/skills/frameworks/effect/effect-backend-structure/references/layout.md +68 -0
- package/dist/skills/frameworks/effect/effect-best-practices/SKILL.md +517 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/anti-patterns.md +392 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/effect-atom-patterns.md +653 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/error-patterns.md +464 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/language-server.md +287 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/layer-patterns.md +495 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/observability-patterns.md +342 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/rpc-cluster-patterns.md +418 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/schema-patterns.md +353 -0
- package/dist/skills/frameworks/effect/effect-best-practices/references/service-patterns.md +299 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/SKILL.md +65 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/agents/openai.yaml +4 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/flow-examples.md +154 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/source-backed-primitives.md +104 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/strategy-matrix.md +34 -0
- package/dist/skills/frameworks/effect/effect-recoverable-actions/references/test-matrix.md +36 -0
- package/dist/skills/frameworks/elysia/elysiajs/SKILL.md +475 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/basic.ts +9 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/body-parser.ts +33 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/complex.ts +112 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/cookie.ts +45 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/error.ts +38 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/file.ts +10 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/guard.ts +34 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/map-response.ts +15 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/redirect.ts +6 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/rename.ts +32 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/schema.ts +61 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/state.ts +6 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/upload-file.ts +20 -0
- package/dist/skills/frameworks/elysia/elysiajs/examples/websocket.ts +25 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/ai-sdk.md +92 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/astro.md +59 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/better-auth.md +117 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/cloudflare-worker.md +95 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/deno.md +34 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/drizzle.md +258 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/expo.md +95 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nextjs.md +103 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nodejs.md +64 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/nuxt.md +67 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/prisma.md +93 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/react-email.md +134 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/sveltekit.md +53 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/tanstack-start.md +87 -0
- package/dist/skills/frameworks/elysia/elysiajs/integrations/vercel.md +55 -0
- package/dist/skills/frameworks/elysia/elysiajs/patterns/mvc.md +380 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/bearer.md +30 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/cors.md +141 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/cron.md +265 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/graphql-apollo.md +90 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/graphql-yoga.md +87 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/html.md +188 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/jwt.md +197 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/openapi.md +246 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/opentelemetry.md +167 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/server-timing.md +71 -0
- package/dist/skills/frameworks/elysia/elysiajs/plugins/static.md +84 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/bun-fullstack-dev-server.md +129 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/cookie.md +187 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/deployment.md +413 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/eden.md +158 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/lifecycle.md +198 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/macro.md +83 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/plugin.md +207 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/route.md +331 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/testing.md +385 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/validation.md +491 -0
- package/dist/skills/frameworks/elysia/elysiajs/references/websocket.md +250 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/.github/workflows/branch-protection.yml +24 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/.github/workflows/deploy.yml +61 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/AGENTS.md +5958 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/SKILL.md +130 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-dto-serialization.md +182 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-interceptors.md +202 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-use-pipes.md +205 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/api-versioning.md +191 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-avoid-circular-deps.md +80 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-feature-modules.md +82 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-module-sharing.md +141 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-single-responsibility.md +106 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-use-events.md +108 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/arch-use-repository-pattern.md +97 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-avoid-n-plus-one.md +139 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-use-migrations.md +129 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/db-use-transactions.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-graceful-shutdown.md +222 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-use-config-module.md +167 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/devops-use-logging.md +232 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-avoid-service-locator.md +104 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-interface-segregation.md +165 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-liskov-substitution.md +221 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-prefer-constructor-injection.md +86 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-scope-awareness.md +94 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/di-use-interfaces-tokens.md +101 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-handle-async-errors.md +125 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-throw-http-exceptions.md +114 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/error-use-exception-filters.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-health-checks.md +226 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-patterns.md +167 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/micro-use-queues.md +252 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-async-hooks.md +109 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-lazy-loading.md +121 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-optimize-database.md +131 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/perf-use-caching.md +128 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-auth-jwt.md +146 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-rate-limiting.md +125 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-sanitize-output.md +139 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-use-guards.md +135 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/security-validate-all-input.md +150 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-e2e-supertest.md +178 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-mock-external-services.md +179 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/rules/test-use-testing-module.md +153 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/build-agents.ts +299 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/build.sh +16 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/package-lock.json +237 -0
- package/dist/skills/frameworks/nestjs/nestjs-best-practices/scripts/package.json +15 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/SKILL.md +208 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/authentication.md +166 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/controllers-routing.md +111 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/dtos-validation.md +153 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/migration-from-express.md +1237 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/services-di.md +140 -0
- package/dist/skills/frameworks/nestjs/nestjs-expert/references/testing-patterns.md +186 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/SKILL.md +153 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/async-patterns.md +87 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/bundling.md +180 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/data-patterns.md +297 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/debug-tricks.md +105 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/directives.md +73 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/error-handling.md +227 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/file-conventions.md +140 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/font.md +245 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/functions.md +108 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/hydration-error.md +91 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/image.md +173 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/metadata.md +301 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/parallel-routes.md +287 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/route-handlers.md +146 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/rsc-boundaries.md +159 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/runtime-selection.md +39 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/scripts.md +141 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/self-hosting.md +371 -0
- package/dist/skills/frameworks/nextjs/next-best-practices/suspense-boundaries.md +67 -0
- package/dist/skills/frameworks/nextjs/next-cache-components/SKILL.md +360 -0
- package/dist/skills/frameworks/react/async-react-patterns/SKILL.md +78 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/AGENTS.md +946 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/SKILL.md +89 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/dist/skills/frameworks/react/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/AGENTS.md +3750 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/SKILL.md +148 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/dist/skills/frameworks/react/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/.claude-plugin/plugin.json +12 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/SKILL.md +1058 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/assets/example-template.txt +14 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/best-practices.md +304 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/common-patterns.md +271 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/example-reference.md +26 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/testing.md +282 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/top-errors.md +332 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/typescript-patterns.md +291 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/references/v4-to-v5-migration.md +231 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/rules/tanstack-query.md +126 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/scripts/example-script.sh +15 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/custom-hooks-pattern.tsx +281 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/devtools-setup.tsx +248 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/error-boundary.tsx +243 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/package.json +31 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/provider-setup.tsx +50 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/query-client-config.ts +72 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-infinite-query.tsx +214 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-mutation-basic.tsx +201 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-mutation-optimistic.tsx +234 -0
- package/dist/skills/frameworks/tanstack-query/tanstack-query/templates/use-query-basic.tsx +119 -0
- package/dist/skills/frameworks/trpc/tanstack-query/.claude-plugin/plugin.json +12 -0
- package/dist/skills/frameworks/trpc/tanstack-query/SKILL.md +1058 -0
- package/dist/skills/frameworks/trpc/tanstack-query/assets/example-template.txt +14 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/best-practices.md +304 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/common-patterns.md +271 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/example-reference.md +26 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/testing.md +282 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/top-errors.md +332 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/typescript-patterns.md +291 -0
- package/dist/skills/frameworks/trpc/tanstack-query/references/v4-to-v5-migration.md +231 -0
- package/dist/skills/frameworks/trpc/tanstack-query/rules/tanstack-query.md +126 -0
- package/dist/skills/frameworks/trpc/tanstack-query/scripts/example-script.sh +15 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/custom-hooks-pattern.tsx +281 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/devtools-setup.tsx +248 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/error-boundary.tsx +243 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/package.json +31 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/provider-setup.tsx +50 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/query-client-config.ts +72 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-infinite-query.tsx +214 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-mutation-basic.tsx +201 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-mutation-optimistic.tsx +234 -0
- package/dist/skills/frameworks/trpc/tanstack-query/templates/use-query-basic.tsx +119 -0
- package/dist/skills/frameworks/turborepo/turborepo/SKILL.md +914 -0
- package/dist/skills/frameworks/turborepo/turborepo/command/turborepo.md +70 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/RULE.md +241 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/dependencies.md +246 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/packages.md +335 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/best-practices/structure.md +270 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/boundaries/RULE.md +126 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/RULE.md +107 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/gotchas.md +169 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/caching/remote-cache.md +127 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/RULE.md +79 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/github-actions.md +162 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/patterns.md +145 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/ci/vercel.md +103 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/cli/RULE.md +100 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/cli/commands.md +297 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/RULE.md +211 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/global-options.md +187 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/gotchas.md +348 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/configuration/tasks.md +285 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/RULE.md +96 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/gotchas.md +141 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/environment/modes.md +101 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/filtering/RULE.md +148 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/filtering/patterns.md +152 -0
- package/dist/skills/frameworks/turborepo/turborepo/references/watch/RULE.md +99 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/README.md +20 -0
- package/docs/reference/dp-requirements.md +210 -0
- package/docs/runbooks/dp-cli-scaffolding.md +187 -0
- package/package.json +24 -50
- package/.eslintignore +0 -4
- package/.eslintrc +0 -127
- package/.prettierignore +0 -4
- package/.prettierrc +0 -7
- package/bin/abstractions/builder.d.ts +0 -4
- package/bin/abstractions/builder.js +0 -7
- package/bin/builders/dotnet/base.d.ts +0 -18
- package/bin/builders/dotnet/base.js +0 -47
- package/bin/builders/dotnet/entity-configuration/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-configuration/index.js +0 -29
- package/bin/builders/dotnet/entity-converter/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-converter/index.js +0 -29
- package/bin/builders/dotnet/entity-model-create/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-create/index.js +0 -29
- package/bin/builders/dotnet/entity-model-dto/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-dto/index.js +0 -29
- package/bin/builders/dotnet/entity-model-list-item-dto/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-list-item-dto/index.js +0 -29
- package/bin/builders/dotnet/entity-model-update/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-model-update/index.js +0 -29
- package/bin/builders/dotnet/entity-search-parameters/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-search-parameters/index.js +0 -29
- package/bin/builders/dotnet/entity-search-query-builder/index.d.ts +0 -8
- package/bin/builders/dotnet/entity-search-query-builder/index.js +0 -29
- package/bin/builders/dotnet/firestore-connector/index.d.ts +0 -8
- package/bin/builders/dotnet/firestore-connector/index.js +0 -29
- package/bin/builders/dotnet/firestore-mapper/index.d.ts +0 -8
- package/bin/builders/dotnet/firestore-mapper/index.js +0 -29
- package/bin/builders/dotnet/types.d.ts +0 -10
- package/bin/builders/dotnet/types.js +0 -3
- package/bin/commands/entity-add/__test__/dotnet/common.d.ts +0 -2
- package/bin/commands/entity-add/__test__/dotnet/common.js +0 -11
- package/bin/commands/entity-add/__test__/dotnet/render.configuration.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.configuration.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.converter.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.converter.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-connector.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-connector.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-mapper.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.firestore-mapper.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-create.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-create.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-dto.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-dto.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-list-item-dto.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-list-item-dto.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.model-update.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.model-update.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.search-parameters.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.search-parameters.spec.js +0 -22
- package/bin/commands/entity-add/__test__/dotnet/render.search-query.spec.d.ts +0 -1
- package/bin/commands/entity-add/__test__/dotnet/render.search-query.spec.js +0 -22
- package/bin/commands/entity-add/index.d.ts +0 -26
- package/bin/commands/entity-add/index.js +0 -44
- package/bin/logging/index.d.ts +0 -8
- package/bin/logging/index.js +0 -28
- package/bin/providers/rendering/base.d.ts +0 -3
- package/bin/providers/rendering/base.js +0 -7
- package/bin/providers/rendering/factory.d.ts +0 -5
- package/bin/providers/rendering/factory.js +0 -16
- package/bin/providers/rendering/handlebars.d.ts +0 -4
- package/bin/providers/rendering/handlebars.js +0 -16
- package/bin/renderer/index.d.ts +0 -6
- package/bin/renderer/index.js +0 -27
- package/bin/run.d.ts +0 -2
- package/bin/run.js +0 -70
- package/bin/services/folders.d.ts +0 -1
- package/bin/services/folders.js +0 -31
- package/bin/types/commands.d.ts +0 -5
- package/bin/types/commands.js +0 -3
- package/bin/utils/collections.d.ts +0 -1
- package/bin/utils/collections.js +0 -6
- package/bin/utils/files.d.ts +0 -3
- package/bin/utils/files.js +0 -19
- package/bin/utils/strings.d.ts +0 -4
- package/bin/utils/strings.js +0 -22
- package/bin/utils/text.d.ts +0 -1
- package/bin/utils/text.js +0 -8
- package/em-cli +0 -0
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.configuration.spec.ts.snap +0 -49
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.converter.spec.ts.snap +0 -53
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.firestore-connector.spec.ts.snap +0 -20
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.firestore-mapper.spec.ts.snap +0 -29
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-create.spec.ts.snap +0 -10
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-dto.spec.ts.snap +0 -9
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-list-item-dto.spec.ts.snap +0 -11
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.model-update.spec.ts.snap +0 -11
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.search-parameters.spec.ts.snap +0 -29
- package/src/commands/entity-add/__test__/dotnet/__snapshots__/render.search-query.spec.ts.snap +0 -42
- package/templates/dotnet/NewEntity/Configuration/<PluralizedEntity>Configuration.cs.template +0 -48
- package/templates/dotnet/NewEntity/Connectors/<PluralizedEntity>FirestoreConnector.cs.template +0 -15
- package/templates/dotnet/NewEntity/Converters/<PluralizedEntity>Converter.cs.template +0 -48
- package/templates/dotnet/NewEntity/Mappers/<PluralizedEntity>FirestoreMapper.cs.template +0 -25
- package/templates/dotnet/NewEntity/Models/<Entity>CreateInput.cs.template +0 -6
- package/templates/dotnet/NewEntity/Models/<Entity>Dto.cs.template +0 -5
- package/templates/dotnet/NewEntity/Models/<Entity>ListItemDto.cs.template +0 -6
- package/templates/dotnet/NewEntity/Models/<Entity>UpdateInput.cs.template +0 -6
- package/templates/dotnet/NewEntity/Search/<PluralizedEntity>QueryBuilder.cs.template +0 -38
- package/templates/dotnet/NewEntity/Search/<PluralizedEntity>SearchParameters.cs.template +0 -24
- package/tsconfig.json +0 -25
|
@@ -0,0 +1,1058 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tanstack-query
|
|
3
|
+
description: |
|
|
4
|
+
Manage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions.
|
|
5
|
+
|
|
6
|
+
Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
|
|
7
|
+
user-invocable: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TanStack Query (React Query) v5
|
|
11
|
+
|
|
12
|
+
**Last Updated**: 2026-01-20
|
|
13
|
+
**Versions**: @tanstack/react-query@5.90.19, @tanstack/react-query-devtools@5.91.2
|
|
14
|
+
**Requires**: React 18.0+ (useSyncExternalStore), TypeScript 4.7+ (recommended)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## v5 New Features
|
|
19
|
+
|
|
20
|
+
### useMutationState - Cross-Component Mutation Tracking
|
|
21
|
+
|
|
22
|
+
Access mutation state from anywhere without prop drilling:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { useMutationState } from '@tanstack/react-query'
|
|
26
|
+
|
|
27
|
+
function GlobalLoadingIndicator() {
|
|
28
|
+
// Get all pending mutations
|
|
29
|
+
const pendingMutations = useMutationState({
|
|
30
|
+
filters: { status: 'pending' },
|
|
31
|
+
select: (mutation) => mutation.state.variables,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
if (pendingMutations.length === 0) return null
|
|
35
|
+
return <div>Saving {pendingMutations.length} items...</div>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Filter by mutation key
|
|
39
|
+
const todoMutations = useMutationState({
|
|
40
|
+
filters: { mutationKey: ['addTodo'] },
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Simplified Optimistic Updates
|
|
45
|
+
|
|
46
|
+
New pattern using `variables` - no cache manipulation, no rollback needed:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
function TodoList() {
|
|
50
|
+
const { data: todos } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
|
|
51
|
+
|
|
52
|
+
const addTodo = useMutation({
|
|
53
|
+
mutationKey: ['addTodo'],
|
|
54
|
+
mutationFn: (newTodo) => api.addTodo(newTodo),
|
|
55
|
+
onSuccess: () => {
|
|
56
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// Show optimistic UI using variables from pending mutations
|
|
61
|
+
const pendingTodos = useMutationState({
|
|
62
|
+
filters: { mutationKey: ['addTodo'], status: 'pending' },
|
|
63
|
+
select: (mutation) => mutation.state.variables,
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<ul>
|
|
68
|
+
{todos?.map(todo => <li key={todo.id}>{todo.title}</li>)}
|
|
69
|
+
{/* Show pending items with visual indicator */}
|
|
70
|
+
{pendingTodos.map((todo, i) => (
|
|
71
|
+
<li key={`pending-${i}`} style={{ opacity: 0.5 }}>{todo.title}</li>
|
|
72
|
+
))}
|
|
73
|
+
</ul>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### throwOnError - Error Boundaries
|
|
79
|
+
|
|
80
|
+
Renamed from `useErrorBoundary` (breaking change):
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
import { QueryErrorResetBoundary } from '@tanstack/react-query'
|
|
84
|
+
import { ErrorBoundary } from 'react-error-boundary'
|
|
85
|
+
|
|
86
|
+
function App() {
|
|
87
|
+
return (
|
|
88
|
+
<QueryErrorResetBoundary>
|
|
89
|
+
{({ reset }) => (
|
|
90
|
+
<ErrorBoundary onReset={reset} fallbackRender={({ resetErrorBoundary }) => (
|
|
91
|
+
<div>
|
|
92
|
+
Error! <button onClick={resetErrorBoundary}>Retry</button>
|
|
93
|
+
</div>
|
|
94
|
+
)}>
|
|
95
|
+
<Todos />
|
|
96
|
+
</ErrorBoundary>
|
|
97
|
+
)}
|
|
98
|
+
</QueryErrorResetBoundary>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function Todos() {
|
|
103
|
+
const { data } = useQuery({
|
|
104
|
+
queryKey: ['todos'],
|
|
105
|
+
queryFn: fetchTodos,
|
|
106
|
+
throwOnError: true, // ✅ v5 (was useErrorBoundary in v4)
|
|
107
|
+
})
|
|
108
|
+
return <div>{data.map(...)}</div>
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Network Mode (Offline/PWA Support)
|
|
113
|
+
|
|
114
|
+
Control behavior when offline:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
const queryClient = new QueryClient({
|
|
118
|
+
defaultOptions: {
|
|
119
|
+
queries: {
|
|
120
|
+
networkMode: 'offlineFirst', // Use cache when offline
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// Per-query override
|
|
126
|
+
useQuery({
|
|
127
|
+
queryKey: ['todos'],
|
|
128
|
+
queryFn: fetchTodos,
|
|
129
|
+
networkMode: 'always', // Always try, even offline (for local APIs)
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
| Mode | Behavior |
|
|
134
|
+
|------|----------|
|
|
135
|
+
| `online` (default) | Only fetch when online |
|
|
136
|
+
| `always` | Always try (useful for local/service worker APIs) |
|
|
137
|
+
| `offlineFirst` | Use cache first, fetch when online |
|
|
138
|
+
|
|
139
|
+
**Detecting paused state:**
|
|
140
|
+
```tsx
|
|
141
|
+
const { isPending, fetchStatus } = useQuery(...)
|
|
142
|
+
// isPending + fetchStatus === 'paused' = offline, waiting for network
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### useQueries with Combine
|
|
146
|
+
|
|
147
|
+
Combine results from parallel queries:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
const results = useQueries({
|
|
151
|
+
queries: userIds.map(id => ({
|
|
152
|
+
queryKey: ['user', id],
|
|
153
|
+
queryFn: () => fetchUser(id),
|
|
154
|
+
})),
|
|
155
|
+
combine: (results) => ({
|
|
156
|
+
data: results.map(r => r.data),
|
|
157
|
+
pending: results.some(r => r.isPending),
|
|
158
|
+
error: results.find(r => r.error)?.error,
|
|
159
|
+
}),
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// Access combined result
|
|
163
|
+
if (results.pending) return <Loading />
|
|
164
|
+
console.log(results.data) // [user1, user2, user3]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### infiniteQueryOptions Helper
|
|
168
|
+
|
|
169
|
+
Type-safe factory for infinite queries (parallel to `queryOptions`):
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
import { infiniteQueryOptions, useInfiniteQuery, prefetchInfiniteQuery } from '@tanstack/react-query'
|
|
173
|
+
|
|
174
|
+
const todosInfiniteOptions = infiniteQueryOptions({
|
|
175
|
+
queryKey: ['todos', 'infinite'],
|
|
176
|
+
queryFn: ({ pageParam }) => fetchTodosPage(pageParam),
|
|
177
|
+
initialPageParam: 0,
|
|
178
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
// Reuse across hooks
|
|
182
|
+
useInfiniteQuery(todosInfiniteOptions)
|
|
183
|
+
useSuspenseInfiniteQuery(todosInfiniteOptions)
|
|
184
|
+
prefetchInfiniteQuery(queryClient, todosInfiniteOptions)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### maxPages - Memory Optimization
|
|
188
|
+
|
|
189
|
+
Limit pages stored in cache for infinite queries:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
useInfiniteQuery({
|
|
193
|
+
queryKey: ['posts'],
|
|
194
|
+
queryFn: ({ pageParam }) => fetchPosts(pageParam),
|
|
195
|
+
initialPageParam: 0,
|
|
196
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
197
|
+
getPreviousPageParam: (firstPage) => firstPage.prevCursor, // Required with maxPages
|
|
198
|
+
maxPages: 3, // Only keep 3 pages in memory
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Note:** `maxPages` requires bi-directional pagination (`getNextPageParam` AND `getPreviousPageParam`).
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Quick Setup
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npm install @tanstack/react-query@latest
|
|
210
|
+
npm install -D @tanstack/react-query-devtools@latest
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Step 2: Provider + Config
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
// src/main.tsx
|
|
217
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
218
|
+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
|
219
|
+
|
|
220
|
+
const queryClient = new QueryClient({
|
|
221
|
+
defaultOptions: {
|
|
222
|
+
queries: {
|
|
223
|
+
staleTime: 1000 * 60 * 5, // 5 min
|
|
224
|
+
gcTime: 1000 * 60 * 60, // 1 hour (v5: renamed from cacheTime)
|
|
225
|
+
refetchOnWindowFocus: false,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
<QueryClientProvider client={queryClient}>
|
|
231
|
+
<App />
|
|
232
|
+
<ReactQueryDevtools initialIsOpen={false} />
|
|
233
|
+
</QueryClientProvider>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Step 3: Query + Mutation Hooks
|
|
237
|
+
|
|
238
|
+
```tsx
|
|
239
|
+
// src/hooks/useTodos.ts
|
|
240
|
+
import { useQuery, useMutation, useQueryClient, queryOptions } from '@tanstack/react-query'
|
|
241
|
+
|
|
242
|
+
// Query options factory (v5 pattern)
|
|
243
|
+
export const todosQueryOptions = queryOptions({
|
|
244
|
+
queryKey: ['todos'],
|
|
245
|
+
queryFn: async () => {
|
|
246
|
+
const res = await fetch('/api/todos')
|
|
247
|
+
if (!res.ok) throw new Error('Failed to fetch')
|
|
248
|
+
return res.json()
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
export function useTodos() {
|
|
253
|
+
return useQuery(todosQueryOptions)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function useAddTodo() {
|
|
257
|
+
const queryClient = useQueryClient()
|
|
258
|
+
return useMutation({
|
|
259
|
+
mutationFn: async (newTodo) => {
|
|
260
|
+
const res = await fetch('/api/todos', {
|
|
261
|
+
method: 'POST',
|
|
262
|
+
headers: { 'Content-Type': 'application/json' },
|
|
263
|
+
body: JSON.stringify(newTodo),
|
|
264
|
+
})
|
|
265
|
+
if (!res.ok) throw new Error('Failed to add')
|
|
266
|
+
return res.json()
|
|
267
|
+
},
|
|
268
|
+
onSuccess: () => {
|
|
269
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
270
|
+
},
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Usage:
|
|
275
|
+
function TodoList() {
|
|
276
|
+
const { data, isPending, isError, error } = useTodos()
|
|
277
|
+
const { mutate } = useAddTodo()
|
|
278
|
+
|
|
279
|
+
if (isPending) return <div>Loading...</div>
|
|
280
|
+
if (isError) return <div>Error: {error.message}</div>
|
|
281
|
+
return <ul>{data.map(todo => <li key={todo.id}>{todo.title}</li>)}</ul>
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Critical Rules
|
|
288
|
+
|
|
289
|
+
### Always Do
|
|
290
|
+
|
|
291
|
+
✅ **Use object syntax for all hooks**
|
|
292
|
+
```tsx
|
|
293
|
+
// v5 ONLY supports this:
|
|
294
|
+
useQuery({ queryKey, queryFn, ...options })
|
|
295
|
+
useMutation({ mutationFn, ...options })
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
✅ **Use array query keys**
|
|
299
|
+
```tsx
|
|
300
|
+
queryKey: ['todos'] // List
|
|
301
|
+
queryKey: ['todos', id] // Detail
|
|
302
|
+
queryKey: ['todos', { filter }] // Filtered
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
✅ **Configure staleTime appropriately**
|
|
306
|
+
```tsx
|
|
307
|
+
staleTime: 1000 * 60 * 5 // 5 min - prevents excessive refetches
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
✅ **Use isPending for initial loading state**
|
|
311
|
+
```tsx
|
|
312
|
+
if (isPending) return <Loading />
|
|
313
|
+
// isPending = no data yet AND fetching
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
✅ **Throw errors in queryFn**
|
|
317
|
+
```tsx
|
|
318
|
+
if (!response.ok) throw new Error('Failed')
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
✅ **Invalidate queries after mutations**
|
|
322
|
+
```tsx
|
|
323
|
+
onSuccess: () => {
|
|
324
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
✅ **Use queryOptions factory for reusable patterns**
|
|
329
|
+
```tsx
|
|
330
|
+
const opts = queryOptions({ queryKey, queryFn })
|
|
331
|
+
useQuery(opts)
|
|
332
|
+
useSuspenseQuery(opts)
|
|
333
|
+
prefetchQuery(opts)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
✅ **Use gcTime (not cacheTime)**
|
|
337
|
+
```tsx
|
|
338
|
+
gcTime: 1000 * 60 * 60 // 1 hour
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Never Do
|
|
342
|
+
|
|
343
|
+
❌ **Never use v4 array/function syntax**
|
|
344
|
+
```tsx
|
|
345
|
+
// v4 (removed in v5):
|
|
346
|
+
useQuery(['todos'], fetchTodos, options) // ❌
|
|
347
|
+
|
|
348
|
+
// v5 (correct):
|
|
349
|
+
useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) // ✅
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
❌ **Never use query callbacks (onSuccess, onError, onSettled in queries)**
|
|
353
|
+
```tsx
|
|
354
|
+
// v5 removed these from queries:
|
|
355
|
+
useQuery({
|
|
356
|
+
queryKey: ['todos'],
|
|
357
|
+
queryFn: fetchTodos,
|
|
358
|
+
onSuccess: (data) => {}, // ❌ Removed in v5
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
// Use useEffect instead:
|
|
362
|
+
const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
|
|
363
|
+
useEffect(() => {
|
|
364
|
+
if (data) {
|
|
365
|
+
// Do something
|
|
366
|
+
}
|
|
367
|
+
}, [data])
|
|
368
|
+
|
|
369
|
+
// Or use mutation callbacks (still supported):
|
|
370
|
+
useMutation({
|
|
371
|
+
mutationFn: addTodo,
|
|
372
|
+
onSuccess: () => {}, // ✅ Still works for mutations
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
❌ **Never use deprecated options**
|
|
377
|
+
```tsx
|
|
378
|
+
// Deprecated in v5:
|
|
379
|
+
cacheTime: 1000 // ❌ Use gcTime instead
|
|
380
|
+
isLoading: true // ❌ Meaning changed, use isPending
|
|
381
|
+
keepPreviousData: true // ❌ Use placeholderData instead
|
|
382
|
+
onSuccess: () => {} // ❌ Removed from queries
|
|
383
|
+
useErrorBoundary: true // ❌ Use throwOnError instead
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
❌ **Never assume isLoading means "no data yet"**
|
|
387
|
+
```tsx
|
|
388
|
+
// v5 changed this:
|
|
389
|
+
isLoading = isPending && isFetching // ❌ Now means "pending AND fetching"
|
|
390
|
+
isPending = no data yet // ✅ Use this for initial load
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
❌ **Never forget initialPageParam for infinite queries**
|
|
394
|
+
```tsx
|
|
395
|
+
// v5 requires this:
|
|
396
|
+
useInfiniteQuery({
|
|
397
|
+
queryKey: ['projects'],
|
|
398
|
+
queryFn: ({ pageParam }) => fetchProjects(pageParam),
|
|
399
|
+
initialPageParam: 0, // ✅ Required in v5
|
|
400
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
401
|
+
})
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
❌ **Never use enabled with useSuspenseQuery**
|
|
405
|
+
```tsx
|
|
406
|
+
// Not allowed:
|
|
407
|
+
useSuspenseQuery({
|
|
408
|
+
queryKey: ['todo', id],
|
|
409
|
+
queryFn: () => fetchTodo(id),
|
|
410
|
+
enabled: !!id, // ❌ Not available with suspense
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
// Use conditional rendering instead:
|
|
414
|
+
{id && <TodoComponent id={id} />}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
❌ **Never rely on refetchOnMount: false for errored queries**
|
|
418
|
+
```tsx
|
|
419
|
+
// Doesn't work - errors are always stale
|
|
420
|
+
useQuery({
|
|
421
|
+
queryKey: ['data'],
|
|
422
|
+
queryFn: failingFetch,
|
|
423
|
+
refetchOnMount: false, // ❌ Ignored when query has error
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
// Use retryOnMount instead
|
|
427
|
+
useQuery({
|
|
428
|
+
queryKey: ['data'],
|
|
429
|
+
queryFn: failingFetch,
|
|
430
|
+
refetchOnMount: false,
|
|
431
|
+
retryOnMount: false, // ✅ Prevents refetch for errored queries
|
|
432
|
+
retry: 0,
|
|
433
|
+
})
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Known Issues Prevention
|
|
439
|
+
|
|
440
|
+
This skill prevents **16 documented issues** from v5 migration, SSR/hydration bugs, and common mistakes:
|
|
441
|
+
|
|
442
|
+
### Issue #1: Object Syntax Required
|
|
443
|
+
**Error**: `useQuery is not a function` or type errors
|
|
444
|
+
**Source**: [v5 Migration Guide](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#removed-overloads-in-favor-of-object-syntax)
|
|
445
|
+
**Why It Happens**: v5 removed all function overloads, only object syntax works
|
|
446
|
+
**Prevention**: Always use `useQuery({ queryKey, queryFn, ...options })`
|
|
447
|
+
|
|
448
|
+
**Before (v4):**
|
|
449
|
+
```tsx
|
|
450
|
+
useQuery(['todos'], fetchTodos, { staleTime: 5000 })
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**After (v5):**
|
|
454
|
+
```tsx
|
|
455
|
+
useQuery({
|
|
456
|
+
queryKey: ['todos'],
|
|
457
|
+
queryFn: fetchTodos,
|
|
458
|
+
staleTime: 5000
|
|
459
|
+
})
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Issue #2: Query Callbacks Removed
|
|
463
|
+
**Error**: Callbacks don't run, TypeScript errors
|
|
464
|
+
**Source**: [v5 Breaking Changes](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#callbacks-on-usequery-and-queryobserver-have-been-removed)
|
|
465
|
+
**Why It Happens**: onSuccess, onError, onSettled removed from queries (still work in mutations)
|
|
466
|
+
**Prevention**: Use `useEffect` for side effects, or move logic to mutation callbacks
|
|
467
|
+
|
|
468
|
+
**Before (v4):**
|
|
469
|
+
```tsx
|
|
470
|
+
useQuery({
|
|
471
|
+
queryKey: ['todos'],
|
|
472
|
+
queryFn: fetchTodos,
|
|
473
|
+
onSuccess: (data) => {
|
|
474
|
+
console.log('Todos loaded:', data)
|
|
475
|
+
},
|
|
476
|
+
})
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**After (v5):**
|
|
480
|
+
```tsx
|
|
481
|
+
const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
|
|
482
|
+
useEffect(() => {
|
|
483
|
+
if (data) {
|
|
484
|
+
console.log('Todos loaded:', data)
|
|
485
|
+
}
|
|
486
|
+
}, [data])
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Issue #3: Status Loading → Pending
|
|
490
|
+
**Error**: UI shows wrong loading state
|
|
491
|
+
**Source**: [v5 Migration: isLoading renamed](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#isloading-and-isfetching-flags)
|
|
492
|
+
**Why It Happens**: `status: 'loading'` renamed to `status: 'pending'`, `isLoading` meaning changed
|
|
493
|
+
**Prevention**: Use `isPending` for initial load, `isLoading` for "pending AND fetching"
|
|
494
|
+
|
|
495
|
+
**Before (v4):**
|
|
496
|
+
```tsx
|
|
497
|
+
const { data, isLoading } = useQuery(...)
|
|
498
|
+
if (isLoading) return <div>Loading...</div>
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**After (v5):**
|
|
502
|
+
```tsx
|
|
503
|
+
const { data, isPending, isLoading } = useQuery(...)
|
|
504
|
+
if (isPending) return <div>Loading...</div>
|
|
505
|
+
// isLoading = isPending && isFetching (fetching for first time)
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Issue #4: cacheTime → gcTime
|
|
509
|
+
**Error**: `cacheTime is not a valid option`
|
|
510
|
+
**Source**: [v5 Migration: gcTime](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#cachetime-has-been-replaced-by-gctime)
|
|
511
|
+
**Why It Happens**: Renamed to better reflect "garbage collection time"
|
|
512
|
+
**Prevention**: Use `gcTime` instead of `cacheTime`
|
|
513
|
+
|
|
514
|
+
**Before (v4):**
|
|
515
|
+
```tsx
|
|
516
|
+
useQuery({
|
|
517
|
+
queryKey: ['todos'],
|
|
518
|
+
queryFn: fetchTodos,
|
|
519
|
+
cacheTime: 1000 * 60 * 60,
|
|
520
|
+
})
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**After (v5):**
|
|
524
|
+
```tsx
|
|
525
|
+
useQuery({
|
|
526
|
+
queryKey: ['todos'],
|
|
527
|
+
queryFn: fetchTodos,
|
|
528
|
+
gcTime: 1000 * 60 * 60,
|
|
529
|
+
})
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Issue #5: useSuspenseQuery + enabled
|
|
533
|
+
**Error**: Type error, enabled option not available
|
|
534
|
+
**Source**: [GitHub Discussion #6206](https://github.com/TanStack/query/discussions/6206)
|
|
535
|
+
**Why It Happens**: Suspense guarantees data is available, can't conditionally disable
|
|
536
|
+
**Prevention**: Use conditional rendering instead of `enabled` option
|
|
537
|
+
|
|
538
|
+
**Before (v4/incorrect):**
|
|
539
|
+
```tsx
|
|
540
|
+
useSuspenseQuery({
|
|
541
|
+
queryKey: ['todo', id],
|
|
542
|
+
queryFn: () => fetchTodo(id),
|
|
543
|
+
enabled: !!id, // ❌ Not allowed
|
|
544
|
+
})
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
**After (v5/correct):**
|
|
548
|
+
```tsx
|
|
549
|
+
// Conditional rendering:
|
|
550
|
+
{id ? (
|
|
551
|
+
<TodoComponent id={id} />
|
|
552
|
+
) : (
|
|
553
|
+
<div>No ID selected</div>
|
|
554
|
+
)}
|
|
555
|
+
|
|
556
|
+
// Inside TodoComponent:
|
|
557
|
+
function TodoComponent({ id }: { id: number }) {
|
|
558
|
+
const { data } = useSuspenseQuery({
|
|
559
|
+
queryKey: ['todo', id],
|
|
560
|
+
queryFn: () => fetchTodo(id),
|
|
561
|
+
// No enabled option needed
|
|
562
|
+
})
|
|
563
|
+
return <div>{data.title}</div>
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Issue #6: initialPageParam Required
|
|
568
|
+
**Error**: `initialPageParam is required` type error
|
|
569
|
+
**Source**: [v5 Migration: Infinite Queries](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#new-required-initialPageParam-option)
|
|
570
|
+
**Why It Happens**: v4 passed `undefined` as first pageParam, v5 requires explicit value
|
|
571
|
+
**Prevention**: Always specify `initialPageParam` for infinite queries
|
|
572
|
+
|
|
573
|
+
**Before (v4):**
|
|
574
|
+
```tsx
|
|
575
|
+
useInfiniteQuery({
|
|
576
|
+
queryKey: ['projects'],
|
|
577
|
+
queryFn: ({ pageParam = 0 }) => fetchProjects(pageParam),
|
|
578
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
579
|
+
})
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
**After (v5):**
|
|
583
|
+
```tsx
|
|
584
|
+
useInfiniteQuery({
|
|
585
|
+
queryKey: ['projects'],
|
|
586
|
+
queryFn: ({ pageParam }) => fetchProjects(pageParam),
|
|
587
|
+
initialPageParam: 0, // ✅ Required
|
|
588
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
589
|
+
})
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
### Issue #7: keepPreviousData Removed
|
|
593
|
+
**Error**: `keepPreviousData is not a valid option`
|
|
594
|
+
**Source**: [v5 Migration: placeholderData](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#removed-keeppreviousdata-in-favor-of-placeholderdata-identity-function)
|
|
595
|
+
**Why It Happens**: Replaced with more flexible `placeholderData` function
|
|
596
|
+
**Prevention**: Use `placeholderData: keepPreviousData` helper
|
|
597
|
+
|
|
598
|
+
**Before (v4):**
|
|
599
|
+
```tsx
|
|
600
|
+
useQuery({
|
|
601
|
+
queryKey: ['todos', page],
|
|
602
|
+
queryFn: () => fetchTodos(page),
|
|
603
|
+
keepPreviousData: true,
|
|
604
|
+
})
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
**After (v5):**
|
|
608
|
+
```tsx
|
|
609
|
+
import { keepPreviousData } from '@tanstack/react-query'
|
|
610
|
+
|
|
611
|
+
useQuery({
|
|
612
|
+
queryKey: ['todos', page],
|
|
613
|
+
queryFn: () => fetchTodos(page),
|
|
614
|
+
placeholderData: keepPreviousData,
|
|
615
|
+
})
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### Issue #8: TypeScript Error Type Default
|
|
619
|
+
**Error**: Type errors with error handling
|
|
620
|
+
**Source**: [v5 Migration: Error Types](https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5#typeerror-is-now-the-default-error)
|
|
621
|
+
**Why It Happens**: v4 used `unknown`, v5 defaults to `Error` type
|
|
622
|
+
**Prevention**: If throwing non-Error types, specify error type explicitly
|
|
623
|
+
|
|
624
|
+
**Before (v4 - error was unknown):**
|
|
625
|
+
```tsx
|
|
626
|
+
const { error } = useQuery({
|
|
627
|
+
queryKey: ['data'],
|
|
628
|
+
queryFn: async () => {
|
|
629
|
+
if (Math.random() > 0.5) throw 'custom error string'
|
|
630
|
+
return data
|
|
631
|
+
},
|
|
632
|
+
})
|
|
633
|
+
// error: unknown
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**After (v5 - specify custom error type):**
|
|
637
|
+
```tsx
|
|
638
|
+
const { error } = useQuery<DataType, string>({
|
|
639
|
+
queryKey: ['data'],
|
|
640
|
+
queryFn: async () => {
|
|
641
|
+
if (Math.random() > 0.5) throw 'custom error string'
|
|
642
|
+
return data
|
|
643
|
+
},
|
|
644
|
+
})
|
|
645
|
+
// error: string | null
|
|
646
|
+
|
|
647
|
+
// Or better: always throw Error objects
|
|
648
|
+
const { error } = useQuery({
|
|
649
|
+
queryKey: ['data'],
|
|
650
|
+
queryFn: async () => {
|
|
651
|
+
if (Math.random() > 0.5) throw new Error('custom error')
|
|
652
|
+
return data
|
|
653
|
+
},
|
|
654
|
+
})
|
|
655
|
+
// error: Error | null (default)
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
### Issue #9: Streaming Server Components Hydration Error
|
|
659
|
+
**Error**: `Hydration failed because the initial UI does not match what was rendered on the server`
|
|
660
|
+
**Source**: [GitHub Issue #9642](https://github.com/TanStack/query/issues/9642)
|
|
661
|
+
**Affects**: v5.82.0+ with streaming SSR (void prefetch pattern)
|
|
662
|
+
**Why It Happens**: Race condition where `hydrate()` resolves synchronously but `query.fetch()` creates async retryer, causing isFetching/isStale mismatch between server and client
|
|
663
|
+
**Prevention**: Don't conditionally render based on `fetchStatus` with `useSuspenseQuery` and streaming prefetch, OR await prefetch instead of void pattern
|
|
664
|
+
|
|
665
|
+
**Before (causes hydration error):**
|
|
666
|
+
```tsx
|
|
667
|
+
// Server: void prefetch
|
|
668
|
+
streamingQueryClient.prefetchQuery({ queryKey: ['data'], queryFn: getData });
|
|
669
|
+
|
|
670
|
+
// Client: conditional render on fetchStatus
|
|
671
|
+
const { data, isFetching } = useSuspenseQuery({ queryKey: ['data'], queryFn: getData });
|
|
672
|
+
return <>{data && <div>{data}</div>} {isFetching && <Loading />}</>;
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**After (workaround):**
|
|
676
|
+
```tsx
|
|
677
|
+
// Option 1: Await prefetch
|
|
678
|
+
await streamingQueryClient.prefetchQuery({ queryKey: ['data'], queryFn: getData });
|
|
679
|
+
|
|
680
|
+
// Option 2: Don't render based on fetchStatus with Suspense
|
|
681
|
+
const { data } = useSuspenseQuery({ queryKey: ['data'], queryFn: getData });
|
|
682
|
+
return <div>{data}</div>; // No conditional on isFetching
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
**Status**: Known issue, being investigated by maintainers. Requires implementation of `getServerSnapshot` in useSyncExternalStore.
|
|
686
|
+
|
|
687
|
+
### Issue #10: useQuery Hydration Error with Prefetching
|
|
688
|
+
**Error**: Text content mismatch during hydration
|
|
689
|
+
**Source**: [GitHub Issue #9399](https://github.com/TanStack/query/issues/9399)
|
|
690
|
+
**Affects**: v5.x with server-side prefetching
|
|
691
|
+
**Why It Happens**: `tryResolveSync` detects resolved promises in RSC payload and extracts data synchronously during hydration, bypassing normal pending state
|
|
692
|
+
**Prevention**: Use `useSuspenseQuery` instead of `useQuery` for SSR, or avoid conditional rendering based on `isLoading`
|
|
693
|
+
|
|
694
|
+
**Before (causes hydration error):**
|
|
695
|
+
```tsx
|
|
696
|
+
// Server Component
|
|
697
|
+
const queryClient = getServerQueryClient();
|
|
698
|
+
await queryClient.prefetchQuery({ queryKey: ['todos'], queryFn: fetchTodos });
|
|
699
|
+
|
|
700
|
+
// Client Component
|
|
701
|
+
function Todos() {
|
|
702
|
+
const { data, isLoading } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos });
|
|
703
|
+
if (isLoading) return <div>Loading...</div>; // Server renders this
|
|
704
|
+
return <div>{data.length} todos</div>; // Client hydrates with this
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**After (workaround):**
|
|
709
|
+
```tsx
|
|
710
|
+
// Use useSuspenseQuery instead
|
|
711
|
+
function Todos() {
|
|
712
|
+
const { data } = useSuspenseQuery({ queryKey: ['todos'], queryFn: fetchTodos });
|
|
713
|
+
return <div>{data.length} todos</div>;
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
**Status**: "At the top of my OSS list of things to fix" - maintainer Ephem (Nov 2025). Requires implementing `getServerSnapshot` in useSyncExternalStore.
|
|
718
|
+
|
|
719
|
+
### Issue #11: refetchOnMount Not Respected for Errored Queries
|
|
720
|
+
**Error**: Queries refetch on mount despite `refetchOnMount: false`
|
|
721
|
+
**Source**: [GitHub Issue #10018](https://github.com/TanStack/query/issues/10018)
|
|
722
|
+
**Affects**: v5.90.16+
|
|
723
|
+
**Why It Happens**: Errored queries with no data are always treated as stale. This is intentional to avoid permanently showing error states
|
|
724
|
+
**Prevention**: Use `retryOnMount: false` instead of (or in addition to) `refetchOnMount: false`
|
|
725
|
+
|
|
726
|
+
**Before (refetches despite setting):**
|
|
727
|
+
```tsx
|
|
728
|
+
const { data, error } = useQuery({
|
|
729
|
+
queryKey: ['data'],
|
|
730
|
+
queryFn: () => { throw new Error('Fails') },
|
|
731
|
+
refetchOnMount: false, // Ignored when query is in error state
|
|
732
|
+
retry: 0,
|
|
733
|
+
});
|
|
734
|
+
// Query refetches every time component mounts
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
**After (correct):**
|
|
738
|
+
```tsx
|
|
739
|
+
const { data, error } = useQuery({
|
|
740
|
+
queryKey: ['data'],
|
|
741
|
+
queryFn: failingFetch,
|
|
742
|
+
refetchOnMount: false,
|
|
743
|
+
retryOnMount: false, // ✅ Prevents refetch on mount for errored queries
|
|
744
|
+
retry: 0,
|
|
745
|
+
});
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
**Status**: Documented behavior (intentional). The name `retryOnMount` is slightly misleading - it controls whether errored queries trigger a new fetch on mount, not automatic retries.
|
|
749
|
+
|
|
750
|
+
### Issue #12: Mutation Callback Signature Breaking Change (v5.89.0)
|
|
751
|
+
**Error**: TypeScript errors in mutation callbacks
|
|
752
|
+
**Source**: [GitHub Issue #9660](https://github.com/TanStack/query/issues/9660)
|
|
753
|
+
**Affects**: v5.89.0+
|
|
754
|
+
**Why It Happens**: `onMutateResult` parameter added between `variables` and `context`, changing callback signatures from 3 params to 4
|
|
755
|
+
**Prevention**: Update all mutation callbacks to accept 4 parameters instead of 3
|
|
756
|
+
|
|
757
|
+
**Before (v5.88 and earlier):**
|
|
758
|
+
```tsx
|
|
759
|
+
useMutation({
|
|
760
|
+
mutationFn: addTodo,
|
|
761
|
+
onError: (error, variables, context) => {
|
|
762
|
+
// context is now onMutateResult, missing final context param
|
|
763
|
+
},
|
|
764
|
+
onSuccess: (data, variables, context) => {
|
|
765
|
+
// Same issue
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
**After (v5.89.0+):**
|
|
771
|
+
```tsx
|
|
772
|
+
useMutation({
|
|
773
|
+
mutationFn: addTodo,
|
|
774
|
+
onError: (error, variables, onMutateResult, context) => {
|
|
775
|
+
// onMutateResult = return value from onMutate
|
|
776
|
+
// context = mutation function context
|
|
777
|
+
},
|
|
778
|
+
onSuccess: (data, variables, onMutateResult, context) => {
|
|
779
|
+
// Correct signature with 4 parameters
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
**Note**: If you don't use `onMutate`, the `onMutateResult` parameter will be undefined. This breaking change was introduced in a patch version.
|
|
785
|
+
|
|
786
|
+
### Issue #13: Readonly Query Keys Break Partial Matching (v5.90.8)
|
|
787
|
+
**Error**: `Type 'readonly ["todos", string]' is not assignable to type '["todos", string]'`
|
|
788
|
+
**Source**: [GitHub Issue #9871](https://github.com/TanStack/query/issues/9871) | Fixed in [PR #9872](https://github.com/TanStack/query/pull/9872)
|
|
789
|
+
**Affects**: v5.90.8 only (fixed in v5.90.9)
|
|
790
|
+
**Why It Happens**: Partial query matching broke TypeScript types for readonly query keys (using `as const`)
|
|
791
|
+
**Prevention**: Upgrade to v5.90.9+ or use type assertions if stuck on v5.90.8
|
|
792
|
+
|
|
793
|
+
**Before (v5.90.8 - TypeScript error):**
|
|
794
|
+
```tsx
|
|
795
|
+
export function todoQueryKey(id?: string) {
|
|
796
|
+
return id ? ['todos', id] as const : ['todos'] as const;
|
|
797
|
+
}
|
|
798
|
+
// Type: readonly ['todos', string] | readonly ['todos']
|
|
799
|
+
|
|
800
|
+
useMutation({
|
|
801
|
+
mutationFn: addTodo,
|
|
802
|
+
onSuccess: () => {
|
|
803
|
+
queryClient.invalidateQueries({
|
|
804
|
+
queryKey: todoQueryKey('123')
|
|
805
|
+
// Error: readonly ['todos', string] not assignable to ['todos', string]
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
});
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
**After (v5.90.9+):**
|
|
812
|
+
```tsx
|
|
813
|
+
// Works correctly with readonly types
|
|
814
|
+
queryClient.invalidateQueries({
|
|
815
|
+
queryKey: todoQueryKey('123') // ✅ No type error
|
|
816
|
+
});
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
**Status**: Fixed in v5.90.9. Particularly affected users of code generators like `openapi-react-query` that produce readonly query keys.
|
|
820
|
+
|
|
821
|
+
### Issue #14: useMutationState Type Inference Lost
|
|
822
|
+
**Error**: `mutation.state.variables` typed as `unknown` instead of actual type
|
|
823
|
+
**Source**: [GitHub Issue #9825](https://github.com/TanStack/query/issues/9825)
|
|
824
|
+
**Affects**: All v5.x versions
|
|
825
|
+
**Why It Happens**: Fuzzy mutation key matching prevents guaranteed type inference (same issue as `queryClient.getQueryCache().find()`)
|
|
826
|
+
**Prevention**: Explicitly cast types in the `select` callback
|
|
827
|
+
|
|
828
|
+
**Before (type inference doesn't work):**
|
|
829
|
+
```tsx
|
|
830
|
+
const addTodo = useMutation({
|
|
831
|
+
mutationKey: ['addTodo'],
|
|
832
|
+
mutationFn: (todo: Todo) => api.addTodo(todo),
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
const pendingTodos = useMutationState({
|
|
836
|
+
filters: { mutationKey: ['addTodo'], status: 'pending' },
|
|
837
|
+
select: (mutation) => {
|
|
838
|
+
return mutation.state.variables; // Type: unknown
|
|
839
|
+
},
|
|
840
|
+
});
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
**After (with explicit cast):**
|
|
844
|
+
```tsx
|
|
845
|
+
const pendingTodos = useMutationState({
|
|
846
|
+
filters: { mutationKey: ['addTodo'], status: 'pending' },
|
|
847
|
+
select: (mutation) => mutation.state.variables as Todo,
|
|
848
|
+
});
|
|
849
|
+
// Or cast the entire state:
|
|
850
|
+
select: (mutation) => mutation.state as MutationState<Todo, Error, Todo, unknown>
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
**Status**: Known limitation of fuzzy matching. No planned fix.
|
|
854
|
+
|
|
855
|
+
### Issue #15: Query Cancellation in StrictMode with fetchQuery
|
|
856
|
+
**Error**: `CancelledError` when using `fetchQuery()` with `useQuery`
|
|
857
|
+
**Source**: [GitHub Issue #9798](https://github.com/TanStack/query/issues/9798)
|
|
858
|
+
**Affects**: Development only (React StrictMode)
|
|
859
|
+
**Why It Happens**: StrictMode causes double mount/unmount. When `useQuery` unmounts and is the last observer, it cancels the query even if `fetchQuery()` is also running
|
|
860
|
+
**Prevention**: This is expected development-only behavior. Doesn't affect production
|
|
861
|
+
|
|
862
|
+
**Example:**
|
|
863
|
+
```tsx
|
|
864
|
+
async function loadData() {
|
|
865
|
+
try {
|
|
866
|
+
const data = await queryClient.fetchQuery({
|
|
867
|
+
queryKey: ['data'],
|
|
868
|
+
queryFn: fetchData,
|
|
869
|
+
});
|
|
870
|
+
console.log('Loaded:', data); // Never logs in StrictMode
|
|
871
|
+
} catch (error) {
|
|
872
|
+
console.error('Failed:', error); // CancelledError
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
function Component() {
|
|
877
|
+
const { data } = useQuery({ queryKey: ['data'], queryFn: fetchData });
|
|
878
|
+
// In StrictMode, component unmounts/remounts, cancelling fetchQuery
|
|
879
|
+
}
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
**Workaround:**
|
|
883
|
+
```tsx
|
|
884
|
+
// Keep query observed with staleTime
|
|
885
|
+
const { data } = useQuery({
|
|
886
|
+
queryKey: ['data'],
|
|
887
|
+
queryFn: fetchData,
|
|
888
|
+
staleTime: Infinity, // Keeps query active
|
|
889
|
+
});
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
**Status**: Expected StrictMode behavior, not a bug. Production builds are unaffected.
|
|
893
|
+
|
|
894
|
+
### Issue #16: invalidateQueries Only Refetches Active Queries
|
|
895
|
+
**Error**: Inactive queries not refetching despite `invalidateQueries()` call
|
|
896
|
+
**Source**: [GitHub Issue #9531](https://github.com/TanStack/query/issues/9531)
|
|
897
|
+
**Affects**: All v5.x versions
|
|
898
|
+
**Why It Happens**: Documentation was misleading - `invalidateQueries()` only refetches "active" queries by default, not "all" queries
|
|
899
|
+
**Prevention**: Use `refetchType: 'all'` to force refetch of inactive queries
|
|
900
|
+
|
|
901
|
+
**Default behavior:**
|
|
902
|
+
```tsx
|
|
903
|
+
// Only active queries (currently being observed) will refetch
|
|
904
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] });
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
**To refetch inactive queries:**
|
|
908
|
+
```tsx
|
|
909
|
+
queryClient.invalidateQueries({
|
|
910
|
+
queryKey: ['todos'],
|
|
911
|
+
refetchType: 'all' // Refetch active AND inactive
|
|
912
|
+
});
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
**Status**: Documentation fixed to clarify "active" queries. This is the intended behavior.
|
|
916
|
+
|
|
917
|
+
---
|
|
918
|
+
|
|
919
|
+
## Community Tips
|
|
920
|
+
|
|
921
|
+
> **Note**: These tips come from community experts and maintainer blogs. Verify against your version.
|
|
922
|
+
|
|
923
|
+
### Tip: Query Options with Multiple Listeners
|
|
924
|
+
|
|
925
|
+
**Source**: [TkDodo's Blog - API Design Lessons](https://tkdodo.eu/blog/react-query-api-design-lessons-learned) | **Confidence**: HIGH
|
|
926
|
+
**Applies to**: v5.27.3+
|
|
927
|
+
|
|
928
|
+
When multiple components use the same query with different options (like `staleTime`), the "last write wins" rule applies for future fetches, but the current in-flight query uses its original options. This can cause unexpected behavior when components mount at different times.
|
|
929
|
+
|
|
930
|
+
**Example of unexpected behavior:**
|
|
931
|
+
```tsx
|
|
932
|
+
// Component A mounts first
|
|
933
|
+
function ComponentA() {
|
|
934
|
+
const { data } = useQuery({
|
|
935
|
+
queryKey: ['todos'],
|
|
936
|
+
queryFn: fetchTodos,
|
|
937
|
+
staleTime: 5000, // Applied initially
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
// Component B mounts while A's query is in-flight
|
|
942
|
+
function ComponentB() {
|
|
943
|
+
const { data } = useQuery({
|
|
944
|
+
queryKey: ['todos'],
|
|
945
|
+
queryFn: fetchTodos,
|
|
946
|
+
staleTime: 60000, // Won't affect current fetch, only future ones
|
|
947
|
+
});
|
|
948
|
+
}
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
**Recommended approach:**
|
|
952
|
+
```tsx
|
|
953
|
+
// Write options as functions that reference latest values
|
|
954
|
+
const getStaleTime = () => shouldUseLongCache ? 60000 : 5000;
|
|
955
|
+
|
|
956
|
+
useQuery({
|
|
957
|
+
queryKey: ['todos'],
|
|
958
|
+
queryFn: fetchTodos,
|
|
959
|
+
staleTime: getStaleTime(), // Evaluated on each render
|
|
960
|
+
});
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
### Tip: refetch() is NOT for Changed Parameters
|
|
964
|
+
|
|
965
|
+
**Source**: [Avoiding Common Mistakes with TanStack Query](https://www.buncolak.com/posts/avoiding-common-mistakes-with-tanstack-query-part-1/) | **Confidence**: HIGH
|
|
966
|
+
|
|
967
|
+
The `refetch()` function should ONLY be used for refreshing with the same parameters (like a manual "reload" button). For new parameters (filters, page numbers, search terms, etc.), include them in the query key instead.
|
|
968
|
+
|
|
969
|
+
**Anti-pattern:**
|
|
970
|
+
```tsx
|
|
971
|
+
// ❌ Wrong - using refetch() for different parameters
|
|
972
|
+
const [page, setPage] = useState(1);
|
|
973
|
+
const { data, refetch } = useQuery({
|
|
974
|
+
queryKey: ['todos'], // Same key for all pages
|
|
975
|
+
queryFn: () => fetchTodos(page),
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
// This refetches with OLD page value, not new one
|
|
979
|
+
<button onClick={() => { setPage(2); refetch(); }}>Next</button>
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
**Correct pattern:**
|
|
983
|
+
```tsx
|
|
984
|
+
// ✅ Correct - include parameters in query key
|
|
985
|
+
const [page, setPage] = useState(1);
|
|
986
|
+
const { data } = useQuery({
|
|
987
|
+
queryKey: ['todos', page], // Key changes with page
|
|
988
|
+
queryFn: () => fetchTodos(page),
|
|
989
|
+
// Query automatically refetches when page changes
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
<button onClick={() => setPage(2)}>Next</button> // Just update state
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
**When to use refetch():**
|
|
996
|
+
```tsx
|
|
997
|
+
// ✅ Manual refresh of same data (refresh button)
|
|
998
|
+
const { data, refetch } = useQuery({
|
|
999
|
+
queryKey: ['todos'],
|
|
1000
|
+
queryFn: fetchTodos,
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
<button onClick={() => refetch()}>Refresh</button> // Same parameters
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
---
|
|
1007
|
+
|
|
1008
|
+
## Key Patterns
|
|
1009
|
+
|
|
1010
|
+
**Dependent Queries** (Query B waits for Query A):
|
|
1011
|
+
```tsx
|
|
1012
|
+
const { data: posts } = useQuery({
|
|
1013
|
+
queryKey: ['users', userId, 'posts'],
|
|
1014
|
+
queryFn: () => fetchUserPosts(userId),
|
|
1015
|
+
enabled: !!user, // Wait for user
|
|
1016
|
+
})
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
**Parallel Queries** (fetch multiple at once):
|
|
1020
|
+
```tsx
|
|
1021
|
+
const results = useQueries({
|
|
1022
|
+
queries: ids.map(id => ({ queryKey: ['todos', id], queryFn: () => fetchTodo(id) })),
|
|
1023
|
+
})
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
**Prefetching** (preload on hover):
|
|
1027
|
+
```tsx
|
|
1028
|
+
queryClient.prefetchQuery({ queryKey: ['todo', id], queryFn: () => fetchTodo(id) })
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
**Infinite Scroll** (useInfiniteQuery):
|
|
1032
|
+
```tsx
|
|
1033
|
+
useInfiniteQuery({
|
|
1034
|
+
queryKey: ['todos', 'infinite'],
|
|
1035
|
+
queryFn: ({ pageParam }) => fetchTodosPage(pageParam),
|
|
1036
|
+
initialPageParam: 0, // Required in v5
|
|
1037
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
1038
|
+
})
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
**Query Cancellation** (auto-cancel on queryKey change):
|
|
1042
|
+
```tsx
|
|
1043
|
+
queryFn: async ({ signal }) => {
|
|
1044
|
+
const res = await fetch(`/api/todos?q=${search}`, { signal })
|
|
1045
|
+
return res.json()
|
|
1046
|
+
}
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
**Data Transformation** (select):
|
|
1050
|
+
```tsx
|
|
1051
|
+
select: (data) => data.filter(todo => todo.completed)
|
|
1052
|
+
```
|
|
1053
|
+
|
|
1054
|
+
**Avoid Request Waterfalls**: Fetch in parallel when possible (don't chain queries unless truly dependent)
|
|
1055
|
+
|
|
1056
|
+
---
|
|
1057
|
+
|
|
1058
|
+
**Official Docs**: https://tanstack.com/query/latest | **v5 Migration**: https://tanstack.com/query/latest/docs/framework/react/guides/migrating-to-v5 | **GitHub**: https://github.com/TanStack/query | **Source Context**: run `opensrc path @tanstack/react-query`, then inspect the returned checkout path
|