@hitch42/applet 0.1.1-beta.1 → 0.1.1-beta.11
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/dist/_internal/client.js +120 -11
- package/dist/_internal/log-context.d.ts +34 -0
- package/dist/_internal/log-context.js +2 -0
- package/dist/_internal/server.d.ts +14 -1
- package/dist/_internal/server.js +122 -118
- package/dist/applet.js +53 -29
- package/dist/build-Bh_S5BUv.js +2 -0
- package/dist/{build-Rk3xDZV7.js → build-CEfFoIZZ.js} +30 -14
- package/dist/ci-BKw14X2h.js +69 -0
- package/dist/client.d.ts +3 -3
- package/dist/{contract-DMrpbaLJ.d.ts → contract-CsUpTBe0.d.ts} +1 -1
- package/dist/{deploy-D3BGDqgC.js → deploy-wGYjwXrx.js} +249 -35
- package/dist/email-DBTVhNB_.js +62 -0
- package/dist/{generate-CH0VQmUi.js → generate-BEIYs17x.js} +79 -25
- package/dist/generate-Dox-OYt6.js +2 -0
- package/dist/headers-DkNr9MLJ.js +17 -0
- package/dist/index.d.ts +123 -11
- package/dist/index.js +142 -26
- package/dist/{init-BS1Y-eNL.js → init-6oGPM46R.js} +17 -18
- package/dist/load-config-xEdTXs0y.js +27 -0
- package/dist/log-context-zu8U9Sjm.js +73 -0
- package/dist/login-CUx3TmFQ.js +12 -0
- package/dist/{logs-m00pzr_O.js → logs-DSjuEN0Q.js} +20 -22
- package/dist/{manifest-BQCAxATS.d.ts → manifest-C6_F4bL8.d.ts} +9 -0
- package/dist/{manifest-DyoJ1MIL.js → manifest-CJSL9GuC.js} +25 -3
- package/dist/me-BW7Paary.js +32 -0
- package/dist/{project-CxN-Dtc7.js → project-BRZGd6xq.js} +227 -34
- package/dist/prompt-ChS-grYO.js +29 -0
- package/dist/query-cache-CXmAyLv3.js +82 -0
- package/dist/react.d.ts +3 -2
- package/dist/react.js +98 -80
- package/dist/schedules-C8_Svr4h.js +42 -0
- package/dist/server.d.ts +9 -4
- package/dist/server.js +29 -8
- package/dist/telephony-protocol-D-nf3Gca.d.ts +76 -0
- package/dist/telephony.d.ts +97 -0
- package/dist/telephony.js +726 -0
- package/dist/{upload-YbRKEqR6.d.ts → upload-DKZzz5kW.d.ts} +6 -6
- package/dist/{variables-CP7Ce3Np.js → variables-DT5RyHdH.js} +14 -39
- package/dist/vite.d.ts +3 -60
- package/dist/vite.js +503 -34
- package/dist/workflow-engine-BOTzURKM.js +111 -0
- package/dist/{auth-DaVK0k5R.js → workspace-D0dnnlxL.js} +75 -40
- package/package.json +19 -6
- package/scaffold/.agents/skills/hitch-applets/SKILL.md +60 -15
- package/scaffold/.agents/skills/hitch-applets/references/email-tracking.md +49 -0
- package/scaffold/.agents/skills/hitch-applets/references/files.md +3 -3
- package/scaffold/.agents/skills/hitch-applets/references/manifest.md +29 -2
- package/scaffold/.agents/skills/hitch-applets/references/markdown.md +2 -0
- package/scaffold/.agents/skills/hitch-applets/references/performance.md +74 -0
- package/scaffold/.agents/skills/hitch-applets/references/records.md +32 -8
- package/scaffold/.agents/skills/hitch-applets/references/schedules.md +7 -2
- package/scaffold/.agents/skills/hitch-applets/references/server.md +0 -3
- package/scaffold/.agents/skills/hitch-applets/references/workflows.md +11 -3
- 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 +2 -2
- package/scaffold/applet/src/client/components/ui/alert.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/button.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/checkbox.tsx +1 -1
- package/scaffold/applet/src/client/components/ui/dialog.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/dropdown-menu.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/input-group.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/select.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/sheet.tsx +2 -2
- package/scaffold/applet/src/client/components/ui/spinner.tsx +2 -1
- package/scaffold/applet/src/client/components/ui/tabs.tsx +1 -1
- package/scaffold/applet/src/client/lib/utils.ts +1 -6
- package/scaffold/applet/src/client/styles/globals.css +2 -0
- package/dist/build-CEku1lyb.js +0 -2
- package/dist/generate-6Nbt7uii.js +0 -2
- package/dist/load-config-BnxocLAQ.js +0 -56
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-router
|
|
3
|
+
description: >-
|
|
4
|
+
React bindings for TanStack Router: RouterProvider, useRouter,
|
|
5
|
+
useRouterState, useMatch, useMatches, useLocation, useSearch,
|
|
6
|
+
useParams, useNavigate, useLoaderData, useLoaderDeps,
|
|
7
|
+
useRouteContext, useBlocker, useCanGoBack, Link, Navigate,
|
|
8
|
+
Outlet, CatchBoundary, ErrorComponent. React-specific patterns
|
|
9
|
+
for hooks, providers, SSR hydration, and createLink with
|
|
10
|
+
forwardRef.
|
|
11
|
+
metadata:
|
|
12
|
+
type: framework
|
|
13
|
+
library: tanstack-router
|
|
14
|
+
library_version: "1.166.2"
|
|
15
|
+
framework: react
|
|
16
|
+
requires:
|
|
17
|
+
- router-core
|
|
18
|
+
sources:
|
|
19
|
+
- TanStack/router:packages/react-router/src
|
|
20
|
+
- TanStack/router:docs/router/guide/creating-a-router.md
|
|
21
|
+
- TanStack/router:docs/router/installation/manual.md
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# React Router (`@tanstack/react-router`)
|
|
25
|
+
|
|
26
|
+
This skill builds on router-core. Read [router-core](router-core/index.md) first for foundational concepts.
|
|
27
|
+
|
|
28
|
+
> **CRITICAL**: TanStack Router types are FULLY INFERRED. Never cast, never annotate inferred values.
|
|
29
|
+
> **CRITICAL**: TanStack Router is CLIENT-FIRST. Loaders run on the client by default, not on the server.
|
|
30
|
+
> **CRITICAL**: Do not confuse `@tanstack/react-router` with `react-router-dom`/`react-router`. They are completely different libraries with different APIs.
|
|
31
|
+
|
|
32
|
+
## Full Setup: File-Based Routing with Vite
|
|
33
|
+
|
|
34
|
+
### 1. Install Dependencies
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @tanstack/react-router
|
|
38
|
+
npm install -D @tanstack/router-plugin @tanstack/react-router-devtools
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Configure Vite Plugin
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// vite.config.ts
|
|
45
|
+
import { defineConfig } from "vite";
|
|
46
|
+
import react from "@vitejs/plugin-react";
|
|
47
|
+
import { tanstackRouter } from "@tanstack/router-plugin/vite";
|
|
48
|
+
|
|
49
|
+
export default defineConfig({
|
|
50
|
+
plugins: [
|
|
51
|
+
// MUST come before react()
|
|
52
|
+
tanstackRouter({
|
|
53
|
+
target: "react",
|
|
54
|
+
autoCodeSplitting: true,
|
|
55
|
+
}),
|
|
56
|
+
react(),
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Create Root Route
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
// src/routes/__root.tsx
|
|
65
|
+
import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
|
|
66
|
+
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
|
67
|
+
|
|
68
|
+
export const Route = createRootRoute({
|
|
69
|
+
component: RootLayout,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
function RootLayout() {
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
<nav>
|
|
76
|
+
<Link to="/" className="[&.active]:font-bold">
|
|
77
|
+
Home
|
|
78
|
+
</Link>
|
|
79
|
+
<Link to="/about" className="[&.active]:font-bold">
|
|
80
|
+
About
|
|
81
|
+
</Link>
|
|
82
|
+
</nav>
|
|
83
|
+
<hr />
|
|
84
|
+
<Outlet />
|
|
85
|
+
<TanStackRouterDevtools />
|
|
86
|
+
</>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 4. Create Route Files
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
// src/routes/index.tsx
|
|
95
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
96
|
+
|
|
97
|
+
export const Route = createFileRoute("/")({
|
|
98
|
+
component: HomePage,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
function HomePage() {
|
|
102
|
+
return <h1>Welcome Home</h1>;
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// src/routes/about.tsx
|
|
108
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
109
|
+
|
|
110
|
+
export const Route = createFileRoute("/about")({
|
|
111
|
+
component: AboutPage,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
function AboutPage() {
|
|
115
|
+
return <h1>About</h1>;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 5. Create Router Instance and Register Types
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// src/main.tsx
|
|
123
|
+
import { StrictMode } from "react";
|
|
124
|
+
import ReactDOM from "react-dom/client";
|
|
125
|
+
import { RouterProvider, createRouter } from "@tanstack/react-router";
|
|
126
|
+
import { routeTree } from "./routeTree.gen";
|
|
127
|
+
|
|
128
|
+
const router = createRouter({ routeTree });
|
|
129
|
+
|
|
130
|
+
// REQUIRED — without this, Link/useNavigate/useSearch have no type safety
|
|
131
|
+
declare module "@tanstack/react-router" {
|
|
132
|
+
interface Register {
|
|
133
|
+
router: typeof router;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const rootElement = document.getElementById("root")!;
|
|
138
|
+
if (!rootElement.innerHTML) {
|
|
139
|
+
const root = ReactDOM.createRoot(rootElement);
|
|
140
|
+
root.render(
|
|
141
|
+
<StrictMode>
|
|
142
|
+
<RouterProvider router={router} />
|
|
143
|
+
</StrictMode>,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Hooks Reference
|
|
149
|
+
|
|
150
|
+
All hooks are imported from `@tanstack/react-router`.
|
|
151
|
+
|
|
152
|
+
### `useRouter()`
|
|
153
|
+
|
|
154
|
+
Access the router instance directly:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
import { useRouter } from "@tanstack/react-router";
|
|
158
|
+
|
|
159
|
+
function InvalidateButton() {
|
|
160
|
+
const router = useRouter();
|
|
161
|
+
return <button onClick={() => router.invalidate()}>Refresh data</button>;
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### `useRouterState()`
|
|
166
|
+
|
|
167
|
+
Subscribe to router state changes. Exposes the entire state and thus incurs
|
|
168
|
+
a performance cost. For matches or location favor `useMatches` and `useLocation`.
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import { useRouterState } from "@tanstack/react-router";
|
|
172
|
+
|
|
173
|
+
function LoadingIndicator() {
|
|
174
|
+
const isLoading = useRouterState({ select: (s) => s.isLoading });
|
|
175
|
+
return isLoading ? <div>Loading...</div> : null;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### `useNavigate()`
|
|
180
|
+
|
|
181
|
+
Programmatic navigation (prefer `<Link>` for user-clickable elements):
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
import { useNavigate } from "@tanstack/react-router";
|
|
185
|
+
|
|
186
|
+
function AfterSubmit() {
|
|
187
|
+
const navigate = useNavigate();
|
|
188
|
+
|
|
189
|
+
const handleSubmit = async () => {
|
|
190
|
+
await saveData();
|
|
191
|
+
navigate({ to: "/posts/$postId", params: { postId: "123" } });
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return <button onClick={handleSubmit}>Save</button>;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### `useSearch({ from })`
|
|
199
|
+
|
|
200
|
+
Read validated search params:
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
import { useSearch } from "@tanstack/react-router";
|
|
204
|
+
|
|
205
|
+
function Pagination() {
|
|
206
|
+
const { page } = useSearch({ from: "/products" });
|
|
207
|
+
return <span>Page {page}</span>;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### `useParams({ from })`
|
|
212
|
+
|
|
213
|
+
Read path params:
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import { useParams } from "@tanstack/react-router";
|
|
217
|
+
|
|
218
|
+
function PostHeader() {
|
|
219
|
+
const { postId } = useParams({ from: "/posts/$postId" });
|
|
220
|
+
return <h2>Post {postId}</h2>;
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### `useLoaderData({ from })`
|
|
225
|
+
|
|
226
|
+
Read data returned from the route loader:
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
import { useLoaderData } from "@tanstack/react-router";
|
|
230
|
+
|
|
231
|
+
function PostContent() {
|
|
232
|
+
const { post } = useLoaderData({ from: "/posts/$postId" });
|
|
233
|
+
return <article>{post.content}</article>;
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `useMatch({ from })`
|
|
238
|
+
|
|
239
|
+
Access the full route match (params, search, loader data, context):
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
import { useMatch } from "@tanstack/react-router";
|
|
243
|
+
|
|
244
|
+
function PostDetails() {
|
|
245
|
+
const match = useMatch({ from: "/posts/$postId" });
|
|
246
|
+
return <div>{match.loaderData.post.title}</div>;
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Other Hooks
|
|
251
|
+
|
|
252
|
+
All imported from `@tanstack/react-router`:
|
|
253
|
+
|
|
254
|
+
- **`useMatches()`** — array of all active route matches (useful for breadcrumbs)
|
|
255
|
+
- **`useRouteContext({ from })`** — read context from `beforeLoad` or parent routes
|
|
256
|
+
- **`useBlocker({ shouldBlockFn })`** — block navigation for unsaved changes
|
|
257
|
+
- **`useCanGoBack()`** — returns `boolean`, check if history has entries to go back to
|
|
258
|
+
- **`useLocation()`** — current parsed location (`pathname`, `search`, `hash`)
|
|
259
|
+
- **`useLinkProps({ to, params?, search? })`** — get `<a>` props for custom link elements
|
|
260
|
+
- **`useMatchRoute()`** — returns a function: `matchRoute({ to }) => match | false`
|
|
261
|
+
|
|
262
|
+
## Components Reference
|
|
263
|
+
|
|
264
|
+
### `RouterProvider`
|
|
265
|
+
|
|
266
|
+
Mount the router at the top of your React tree:
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
<RouterProvider router={router} />
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### `Link`
|
|
273
|
+
|
|
274
|
+
Type-safe navigation link with `<a>` semantics:
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
<Link to="/posts/$postId" params={{ postId: "42" }}>
|
|
278
|
+
View Post
|
|
279
|
+
</Link>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### `Outlet`
|
|
283
|
+
|
|
284
|
+
Renders the matched child route component:
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
function Layout() {
|
|
288
|
+
return (
|
|
289
|
+
<div>
|
|
290
|
+
<Sidebar />
|
|
291
|
+
<main>
|
|
292
|
+
<Outlet />
|
|
293
|
+
</main>
|
|
294
|
+
</div>
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### `Navigate`
|
|
300
|
+
|
|
301
|
+
Declarative redirect component:
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
import { Navigate } from "@tanstack/react-router";
|
|
305
|
+
|
|
306
|
+
function OldPage() {
|
|
307
|
+
return <Navigate to="/new-page" />;
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### `Await`
|
|
312
|
+
|
|
313
|
+
Renders deferred data from unawaited loader promises with Suspense:
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { Await } from "@tanstack/react-router";
|
|
317
|
+
import { Suspense } from "react";
|
|
318
|
+
|
|
319
|
+
function PostWithComments() {
|
|
320
|
+
const { deferredComments } = Route.useLoaderData();
|
|
321
|
+
return (
|
|
322
|
+
<div>
|
|
323
|
+
<h1>Post</h1>
|
|
324
|
+
<Suspense fallback={<div>Loading comments...</div>}>
|
|
325
|
+
<Await promise={deferredComments}>
|
|
326
|
+
{(comments) => (
|
|
327
|
+
<ul>
|
|
328
|
+
{comments.map((c) => (
|
|
329
|
+
<li key={c.id}>{c.text}</li>
|
|
330
|
+
))}
|
|
331
|
+
</ul>
|
|
332
|
+
)}
|
|
333
|
+
</Await>
|
|
334
|
+
</Suspense>
|
|
335
|
+
</div>
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### `CatchBoundary`
|
|
341
|
+
|
|
342
|
+
Error boundary for component-level error handling (route-level errors use `errorComponent` route option):
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
import { CatchBoundary } from "@tanstack/react-router";
|
|
346
|
+
<CatchBoundary
|
|
347
|
+
getResetKey={() => "widget"}
|
|
348
|
+
onCatch={(error) => console.error(error)}
|
|
349
|
+
errorComponent={({ error }) => <div>{String(error)}</div>}
|
|
350
|
+
>
|
|
351
|
+
<RiskyWidget />
|
|
352
|
+
</CatchBoundary>;
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## React-Specific Patterns
|
|
356
|
+
|
|
357
|
+
### Custom Link Component with `createLink`
|
|
358
|
+
|
|
359
|
+
Wrap `Link` in a custom component while preserving type safety:
|
|
360
|
+
|
|
361
|
+
```tsx
|
|
362
|
+
import { createLink } from "@tanstack/react-router";
|
|
363
|
+
import { forwardRef, type ComponentPropsWithoutRef } from "react";
|
|
364
|
+
|
|
365
|
+
const StyledLinkComponent = forwardRef<HTMLAnchorElement, ComponentPropsWithoutRef<"a">>(
|
|
366
|
+
(props, ref) => <a ref={ref} {...props} className={`styled-link ${props.className ?? ""}`} />,
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
const StyledLink = createLink(StyledLinkComponent);
|
|
370
|
+
|
|
371
|
+
// Usage — same type-safe props as Link
|
|
372
|
+
function Nav() {
|
|
373
|
+
return (
|
|
374
|
+
<StyledLink to="/posts/$postId" params={{ postId: "42" }}>
|
|
375
|
+
Post
|
|
376
|
+
</StyledLink>
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Reusable Components with Router Hooks
|
|
382
|
+
|
|
383
|
+
To create a component that uses router hooks across multiple routes, pass a union of route paths as the `from` prop:
|
|
384
|
+
|
|
385
|
+
```tsx
|
|
386
|
+
function PostIdDisplay({ from }: { from: '/posts/$id' | '/drafts/$id' }) {
|
|
387
|
+
const { id } = useParams({ from })
|
|
388
|
+
return <span>ID: {id}</span>
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Usage in different route components
|
|
392
|
+
<PostIdDisplay from="/posts/$id" />
|
|
393
|
+
<PostIdDisplay from="/drafts/$id" />
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
This pattern avoids `strict: false` (which returns an imprecise union) while keeping the component reusable across specific known routes.
|
|
397
|
+
|
|
398
|
+
### Auth Provider Must Wrap RouterProvider
|
|
399
|
+
|
|
400
|
+
If routes use auth context (via `createRootRouteWithContext`), the auth provider must be an ancestor of `RouterProvider`:
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
// CORRECT — AuthProvider wraps RouterProvider
|
|
404
|
+
function App() {
|
|
405
|
+
return (
|
|
406
|
+
<AuthProvider>
|
|
407
|
+
<RouterProvider router={router} />
|
|
408
|
+
</AuthProvider>
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// WRONG — RouterProvider outside auth provider
|
|
413
|
+
function App() {
|
|
414
|
+
return (
|
|
415
|
+
<RouterProvider router={router}>
|
|
416
|
+
<AuthProvider>{/* ... */}</AuthProvider>
|
|
417
|
+
</RouterProvider>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Or use the `Wrap` router option to provide context without wrapping externally:
|
|
423
|
+
|
|
424
|
+
```tsx
|
|
425
|
+
const router = createRouter({
|
|
426
|
+
routeTree,
|
|
427
|
+
Wrap: ({ children }) => (
|
|
428
|
+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
429
|
+
),
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Common Mistakes
|
|
434
|
+
|
|
435
|
+
### 1. HIGH: Using React hooks in `beforeLoad` or `loader`
|
|
436
|
+
|
|
437
|
+
`beforeLoad` and `loader` are NOT React components — they are plain async functions. React hooks cannot be called in them. Pass auth state via router context instead.
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
// WRONG — useAuth is a React hook, cannot be called here
|
|
441
|
+
beforeLoad: () => {
|
|
442
|
+
const auth = useAuth();
|
|
443
|
+
if (!auth.user) throw redirect({ to: "/login" });
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// CORRECT — read auth from router context
|
|
447
|
+
beforeLoad: ({ context }) => {
|
|
448
|
+
if (!context.auth.isAuthenticated) {
|
|
449
|
+
throw redirect({ to: "/login" });
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### 2. HIGH: Wrapping RouterProvider inside an auth provider incorrectly
|
|
455
|
+
|
|
456
|
+
Create the router once with an `undefined!` placeholder, then inject live auth via `RouterProvider`'s `context` prop. Do NOT recreate the router on auth changes — this resets caches and rebuilds the tree.
|
|
457
|
+
|
|
458
|
+
```tsx
|
|
459
|
+
// CORRECT — create router once, inject live auth via context prop
|
|
460
|
+
const router = createRouter({
|
|
461
|
+
routeTree,
|
|
462
|
+
context: { auth: undefined! }, // placeholder, filled by RouterProvider
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
function InnerApp() {
|
|
466
|
+
const auth = useAuth();
|
|
467
|
+
return <RouterProvider router={router} context={{ auth }} />;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function App() {
|
|
471
|
+
return (
|
|
472
|
+
<AuthProvider>
|
|
473
|
+
<InnerApp />
|
|
474
|
+
</AuthProvider>
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### 3. MEDIUM: Missing Suspense boundary for `Await`/deferred data
|
|
480
|
+
|
|
481
|
+
`Await` requires a `<Suspense>` ancestor. Without it, the deferred promise has no fallback UI and throws.
|
|
482
|
+
|
|
483
|
+
```tsx
|
|
484
|
+
// WRONG — no Suspense boundary
|
|
485
|
+
<Await promise={deferredData}>{(data) => <div>{data}</div>}</Await>
|
|
486
|
+
|
|
487
|
+
// CORRECT — wrap in Suspense
|
|
488
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
489
|
+
<Await promise={deferredData}>{(data) => <div>{data}</div>}</Await>
|
|
490
|
+
</Suspense>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## Cross-References
|
|
494
|
+
|
|
495
|
+
- [router-core/SKILL.md](router-core/index.md) — all sub-skills for domain-specific patterns (search params, data loading, navigation, auth, SSR, etc.)
|