@rangojs/router 0.0.0-experimental.19 → 0.0.0-experimental.1c0bdfad
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 +17 -0
- package/README.md +291 -61
- package/dist/bin/rango.js +544 -143
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3744 -1329
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +67 -13
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +312 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +247 -23
- package/skills/caching/SKILL.md +322 -19
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +282 -60
- package/skills/host-router/SKILL.md +278 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +50 -6
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +297 -31
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +771 -0
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +203 -7
- package/skills/prerender/SKILL.md +155 -111
- package/skills/rango/SKILL.md +251 -23
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +123 -48
- package/skills/route/SKILL.md +104 -9
- package/skills/router-setup/SKILL.md +124 -11
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +125 -222
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/typesafety/SKILL.md +357 -52
- package/skills/use-cache/SKILL.md +46 -14
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +67 -40
- package/src/bin/rango.ts +18 -0
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +197 -150
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +200 -30
- package/src/browser/navigation-client.ts +217 -58
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +76 -67
- package/src/browser/navigation-transaction.ts +18 -66
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +187 -112
- package/src/browser/prefetch/cache.ts +312 -30
- package/src/browser/prefetch/fetch.ts +344 -47
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +126 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +125 -18
- package/src/browser/react/NavigationProvider.tsx +135 -120
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +23 -69
- package/src/browser/react/use-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +46 -11
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +80 -5
- package/src/browser/rsc-router.tsx +226 -75
- package/src/browser/scroll-restoration.ts +54 -42
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +619 -442
- package/src/browser/types.ts +115 -11
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +7 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +182 -37
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +125 -24
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +392 -106
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +29 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +214 -48
- package/src/cache/cache-scope.ts +236 -89
- package/src/cache/cache-tag.ts +103 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2224 -171
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +11 -17
- package/src/cache/document-cache.ts +89 -27
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +11 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +31 -31
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +55 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +45 -21
- package/src/client.tsx +120 -336
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +84 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +70 -22
- package/src/handles/MetaTags.tsx +56 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +95 -0
- package/src/handles/is-thenable.ts +19 -0
- package/src/handles/meta.ts +51 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -5
- package/src/host/pattern-matcher.ts +23 -52
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +79 -29
- package/src/index.ts +149 -65
- package/src/internal-debug.ts +11 -10
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +63 -26
- package/src/prerender.ts +198 -82
- package/src/redirect-origin.ts +100 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +469 -276
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +113 -37
- package/src/route-definition/index.ts +3 -3
- package/src/route-definition/redirect.ts +53 -12
- package/src/route-definition/resolve-handler-use.ts +161 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -17
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +164 -17
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +45 -22
- package/src/router/handler-context.ts +110 -39
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +50 -24
- package/src/router/lazy-includes.ts +19 -53
- package/src/router/loader-resolution.ts +274 -56
- package/src/router/logging.ts +5 -8
- package/src/router/manifest.ts +49 -45
- package/src/router/match-api.ts +121 -205
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +33 -6
- package/src/router/match-middleware/cache-lookup.ts +214 -263
- package/src/router/match-middleware/cache-store.ts +73 -33
- package/src/router/match-middleware/intercept-resolution.ts +8 -28
- package/src/router/match-middleware/segment-resolution.ts +52 -18
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +104 -49
- package/src/router/metrics.ts +217 -26
- package/src/router/middleware-types.ts +24 -110
- package/src/router/middleware.ts +384 -197
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +148 -91
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +199 -56
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +144 -74
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +8 -28
- package/src/router/router-interfaces.ts +129 -36
- package/src/router/router-options.ts +185 -23
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +281 -76
- package/src/router/segment-resolution/helpers.ts +116 -31
- package/src/router/segment-resolution/loader-cache.ts +63 -37
- package/src/router/segment-resolution/revalidation.ts +493 -391
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +8 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +161 -199
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +180 -58
- package/src/router/types.ts +10 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +182 -54
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +702 -460
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -25
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +127 -31
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +98 -19
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +99 -189
- package/src/rsc/rsc-rendering.ts +126 -106
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +269 -114
- package/src/rsc/ssr-setup.ts +144 -0
- package/src/rsc/types.ts +34 -6
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +49 -41
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +149 -0
- package/src/segment-system.tsx +281 -129
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +317 -63
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +40 -38
- package/src/server/loader-registry.ts +26 -46
- package/src/server/request-context.ts +425 -177
- package/src/server.ts +6 -0
- package/src/ssr/index.tsx +25 -16
- package/src/static-handler.ts +27 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +701 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +257 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +371 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +343 -0
- package/src/testing/render-route.tsx +581 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +20 -58
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +3 -19
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +17 -8
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +236 -88
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +44 -15
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +10 -45
- package/src/types/route-entry.ts +19 -7
- package/src/types/segments.ts +37 -19
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +58 -11
- package/src/urls/path-helper.ts +57 -111
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +346 -89
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +64 -91
- package/src/vite/discovery/discover-routers.ts +147 -88
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +247 -145
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +61 -13
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +10 -3
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +155 -65
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- package/src/vite/plugins/client-ref-dedup.ts +120 -0
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +49 -98
- package/src/vite/plugins/expose-id-utils.ts +96 -51
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +553 -317
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/version-injector.ts +21 -25
- package/src/vite/plugins/version-plugin.ts +46 -37
- package/src/vite/plugins/virtual-entries.ts +13 -18
- package/src/vite/rango.ts +241 -287
- package/src/vite/router-discovery.ts +956 -149
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/directive-prologue.ts +40 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +141 -34
- package/src/vite/utils/shared-utils.ts +92 -42
- package/CLAUDE.md +0 -5
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -6
- package/src/network-error-thrower.tsx +0 -23
- package/src/route-definition/route-function.ts +0 -119
- package/src/router/middleware-cookies.ts +0 -55
package/skills/hooks/SKILL.md
CHANGED
|
@@ -6,7 +6,8 @@ argument-hint: [hook-name]
|
|
|
6
6
|
|
|
7
7
|
# Client-Side React Hooks
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Import the hooks and components in this skill from `@rangojs/router/client`.
|
|
10
|
+
The root `@rangojs/router` entrypoint is for server/RSC APIs and shared types.
|
|
10
11
|
|
|
11
12
|
## Navigation Hooks
|
|
12
13
|
|
|
@@ -57,19 +58,39 @@ function NavigationControls() {
|
|
|
57
58
|
}
|
|
58
59
|
```
|
|
59
60
|
|
|
61
|
+
#### Skipping revalidation
|
|
62
|
+
|
|
63
|
+
Pass `revalidate: false` to skip the RSC server fetch for same-pathname navigations (search param or hash changes). The URL updates and all hooks re-render, but server components stay as-is.
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
// Update search params without server round-trip
|
|
67
|
+
router.push("/products?color=blue", { revalidate: false });
|
|
68
|
+
router.replace("/products?page=3", { revalidate: false });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If the pathname changes, `revalidate: false` is silently ignored and a full navigation occurs. This also works on `<Link>`:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
<Link to="/products?color=blue" revalidate={false}>
|
|
75
|
+
Blue
|
|
76
|
+
</Link>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Plain `<a>` tags can opt in via `data-revalidate="false"`.
|
|
80
|
+
|
|
60
81
|
### useSegments()
|
|
61
82
|
|
|
62
83
|
Access current URL path and matched route segments:
|
|
63
84
|
|
|
64
85
|
```tsx
|
|
65
86
|
"use client";
|
|
66
|
-
import { useSegments } from "@rangojs/router";
|
|
87
|
+
import { useSegments } from "@rangojs/router/client";
|
|
67
88
|
|
|
68
89
|
function Breadcrumbs() {
|
|
69
90
|
const { path, segmentIds, location } = useSegments();
|
|
70
91
|
|
|
71
|
-
// path: ["
|
|
72
|
-
// segmentIds: ["
|
|
92
|
+
// path: ["shop", "products", "123"] (split on "/", no leading slash on any element)
|
|
93
|
+
// segmentIds: ["L0", "L0L1", "L0L1R0"] (opaque internal short-codes, not route names)
|
|
73
94
|
// location: URL object
|
|
74
95
|
|
|
75
96
|
return <nav>{path.join(" > ")}</nav>;
|
|
@@ -107,7 +128,7 @@ Access loader data (strict - data guaranteed):
|
|
|
107
128
|
|
|
108
129
|
```tsx
|
|
109
130
|
"use client";
|
|
110
|
-
import { useLoader } from "@rangojs/router";
|
|
131
|
+
import { useLoader } from "@rangojs/router/client";
|
|
111
132
|
import { ProductLoader } from "../loaders/product";
|
|
112
133
|
|
|
113
134
|
function ProductPrice() {
|
|
@@ -143,7 +164,7 @@ Access loader with on-demand fetching (flexible):
|
|
|
143
164
|
|
|
144
165
|
```tsx
|
|
145
166
|
"use client";
|
|
146
|
-
import { useFetchLoader } from "@rangojs/router";
|
|
167
|
+
import { useFetchLoader } from "@rangojs/router/client";
|
|
147
168
|
import { SearchLoader } from "../loaders/search";
|
|
148
169
|
|
|
149
170
|
function SearchResults() {
|
|
@@ -169,6 +190,141 @@ function SearchResults() {
|
|
|
169
190
|
}
|
|
170
191
|
```
|
|
171
192
|
|
|
193
|
+
**Shared refetch behavior**:
|
|
194
|
+
|
|
195
|
+
When the loader is registered on the route via `loader()`, a plain
|
|
196
|
+
`load()` call (no options, or a trivially-defaulted GET with no
|
|
197
|
+
`params` and no `body`) broadcasts its result to every component
|
|
198
|
+
reading the same loader id. Layout, page, and parallel-slot reads
|
|
199
|
+
all converge on the new value:
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
// Layout button calls load() — the page read below sees the update too.
|
|
203
|
+
function Layout() {
|
|
204
|
+
const { data, load } = useLoader(CartLoader);
|
|
205
|
+
return <button onClick={() => load()}>Refresh ({data.count})</button>;
|
|
206
|
+
}
|
|
207
|
+
function Page() {
|
|
208
|
+
const { data } = useLoader(CartLoader); // updates with the layout's load()
|
|
209
|
+
return <span>{data.count} items</span>;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`isLoading` and `error` follow the same scope. `throwOnError: true`
|
|
214
|
+
render-throws are scoped to the **originating** hook — sibling readers
|
|
215
|
+
see the error in their `error` state but their boundaries are not
|
|
216
|
+
triggered by someone else's failure. A successful follow-up `load()`
|
|
217
|
+
clears the shared error.
|
|
218
|
+
|
|
219
|
+
**`load()` calls that stay local** (no broadcast, per-hook state, same
|
|
220
|
+
semantics as the old per-component `useState`):
|
|
221
|
+
|
|
222
|
+
- `load({ params: { ... } })` — explicit params.
|
|
223
|
+
- `load({ method: "POST", body })` — mutations.
|
|
224
|
+
- Any `load()` on a `useFetchLoader(loader)` whose loader is **not**
|
|
225
|
+
registered on the current route. Two unrelated components calling
|
|
226
|
+
`load()` on the same fetchable-but-unregistered loader keep
|
|
227
|
+
independent results.
|
|
228
|
+
|
|
229
|
+
So the search/list pattern still works — two components calling
|
|
230
|
+
`load({ params: { q } })` with different `q` values each keep their
|
|
231
|
+
own result; they do not collapse to last-write-wins through a shared
|
|
232
|
+
store.
|
|
233
|
+
|
|
234
|
+
**Scoping refetch with a `key`**:
|
|
235
|
+
|
|
236
|
+
Pass a `key` to partition the shared refresh store. Only hooks using the
|
|
237
|
+
**same** `key` refresh together when one of them calls `load()`. This is a
|
|
238
|
+
client-side refresh identity only — it never changes the request sent to the
|
|
239
|
+
server, and is unrelated to the server `cache({ key })` option and to
|
|
240
|
+
`revalidate()`.
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
// Two independent dashboards using the same loader. Without a key, one
|
|
244
|
+
// dashboard's load() would flip the other's spinner and value. With a key,
|
|
245
|
+
// they refresh independently.
|
|
246
|
+
function Dashboard({ id }: { id: string }) {
|
|
247
|
+
const { data, load } = useLoader(StatsLoader, { key: `dashboard:${id}` });
|
|
248
|
+
return <button onClick={() => load()}>Refresh {data.total}</button>;
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The `key` widens sharing in two ways the default cannot:
|
|
253
|
+
|
|
254
|
+
- **Parameterized GETs share.** `useFetchLoader(SearchLoader, { key: q })`
|
|
255
|
+
with the same `q` in two components share one result and refresh together —
|
|
256
|
+
a keyed `load({ params: { q } })` broadcasts to the group instead of staying
|
|
257
|
+
local. (Mutations — non-GET or `body` — stay local even with a key.)
|
|
258
|
+
- **Unregistered loaders share.** A `key` makes `useFetchLoader` of a loader
|
|
259
|
+
that is **not** registered on the route share too, letting unrelated
|
|
260
|
+
components opt into a common refresh group.
|
|
261
|
+
|
|
262
|
+
Lifecycle: a keyed read of an unregistered loader is reference-counted — its
|
|
263
|
+
shared value lives as long as at least one component using that key is mounted.
|
|
264
|
+
A persistent component (e.g. a header) keeps the value across navigations; a
|
|
265
|
+
route-scoped component's value is reclaimed when it unmounts. Registered-loader
|
|
266
|
+
reads (keyed or not) reset on navigation from fresh route data, as before.
|
|
267
|
+
|
|
268
|
+
**Refreshing multiple loaders together (`refreshGroup` + `useRefreshLoaders`)**:
|
|
269
|
+
|
|
270
|
+
`key` groups readers of one loader. To refresh **different** loaders together,
|
|
271
|
+
tag them with a shared `refreshGroup` name and trigger them with
|
|
272
|
+
`useRefreshLoaders()`. The hook takes no argument; you pass the group(s) to the
|
|
273
|
+
function it returns, so one `useRefreshLoaders()` can refresh different groups
|
|
274
|
+
depending on context. A read may carry **several** tags — pass an array — and is
|
|
275
|
+
refreshed when **any** of its groups is refreshed:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
function Profile() {
|
|
279
|
+
const { data } = useLoader(ProfileLoader, {
|
|
280
|
+
key: userId,
|
|
281
|
+
refreshGroup: "account",
|
|
282
|
+
});
|
|
283
|
+
return <span>{data.name}</span>;
|
|
284
|
+
}
|
|
285
|
+
function Orders() {
|
|
286
|
+
// Tagged into two groups: refreshed by "account" (the whole set) or the
|
|
287
|
+
// finer "orders" tag.
|
|
288
|
+
const { data } = useLoader(OrdersLoader, {
|
|
289
|
+
key: userId,
|
|
290
|
+
refreshGroup: ["account", "orders"],
|
|
291
|
+
});
|
|
292
|
+
return <span>{data.count} orders</span>;
|
|
293
|
+
}
|
|
294
|
+
function RefreshButtons() {
|
|
295
|
+
const refresh = useRefreshLoaders();
|
|
296
|
+
return (
|
|
297
|
+
<>
|
|
298
|
+
<button onClick={() => refresh("account")}>Refresh account</button>
|
|
299
|
+
<button onClick={() => refresh("orders")}>Refresh orders only</button>
|
|
300
|
+
<button onClick={() => refresh(["account", "orders"])}>
|
|
301
|
+
Refresh both
|
|
302
|
+
</button>
|
|
303
|
+
</>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`refresh(groups)` accepts one name or an array and re-runs every currently-mounted
|
|
309
|
+
member tagged with **any** of them, with a **plain GET** against the current route
|
|
310
|
+
URL — no params, no body, no mutation methods, because a group spans loaders with
|
|
311
|
+
different shapes. A member that sits in two of the requested groups is fetched
|
|
312
|
+
once (members are unioned and deduped by read). It returns a promise that resolves
|
|
313
|
+
when all members settle and **rejects with an `AggregateError`** if any fail;
|
|
314
|
+
group refresh never render-throws, so handle failures at the await site
|
|
315
|
+
(`await refresh("account").catch(...)`). Each failing member also exposes its
|
|
316
|
+
error via its own read's `error`.
|
|
317
|
+
|
|
318
|
+
Multiple tags give you granular vs. whole-set refresh from one place: a coarse
|
|
319
|
+
tag (`"account"`) covers everything, while a finer tag (`"orders"`) targets a
|
|
320
|
+
subset. Sharing within a group is opt-in via `key`: members that share a `key`
|
|
321
|
+
share one value (and one fetch); a grouped reader **without** a `key` gets its own
|
|
322
|
+
private bucket, so a group refresh updates only that read and never leaks into
|
|
323
|
+
unrelated unkeyed reads of the same loader. A bucket may belong to several groups
|
|
324
|
+
at once (one read tagged with multiple names, or different reads tagging the same
|
|
325
|
+
keyed bucket with different names). Keep parameterized loaders on the single-loader
|
|
326
|
+
`key` — a plain-GET group refresh sends no params.
|
|
327
|
+
|
|
172
328
|
**Load options**:
|
|
173
329
|
|
|
174
330
|
```tsx
|
|
@@ -197,7 +353,7 @@ server, JSON bodies are available via `ctx.body` and FormData bodies via `ctx.fo
|
|
|
197
353
|
|
|
198
354
|
```tsx
|
|
199
355
|
"use client";
|
|
200
|
-
import { useFetchLoader } from "@rangojs/router";
|
|
356
|
+
import { useFetchLoader } from "@rangojs/router/client";
|
|
201
357
|
import { FileUploadLoader } from "../loaders/upload";
|
|
202
358
|
|
|
203
359
|
function FileUploader() {
|
|
@@ -238,22 +394,6 @@ export const FileUploadLoader = createLoader(async (ctx) => {
|
|
|
238
394
|
}, true); // true = fetchable (can be called from the client via load())
|
|
239
395
|
```
|
|
240
396
|
|
|
241
|
-
### useLoaderData()
|
|
242
|
-
|
|
243
|
-
Get all loader data in current context:
|
|
244
|
-
|
|
245
|
-
```tsx
|
|
246
|
-
"use client";
|
|
247
|
-
import { useLoaderData } from "@rangojs/router";
|
|
248
|
-
|
|
249
|
-
function DebugPanel() {
|
|
250
|
-
const allData = useLoaderData();
|
|
251
|
-
// Record<string, any> - Map of loader ID to data
|
|
252
|
-
|
|
253
|
-
return <pre>{JSON.stringify(allData, null, 2)}</pre>;
|
|
254
|
-
}
|
|
255
|
-
```
|
|
256
|
-
|
|
257
397
|
## Handle Hooks
|
|
258
398
|
|
|
259
399
|
### useHandle()
|
|
@@ -262,8 +402,7 @@ Access accumulated handle data from route segments:
|
|
|
262
402
|
|
|
263
403
|
```tsx
|
|
264
404
|
"use client";
|
|
265
|
-
import { useHandle } from "@rangojs/router";
|
|
266
|
-
import { Breadcrumbs } from "../handles/breadcrumbs";
|
|
405
|
+
import { useHandle, Breadcrumbs } from "@rangojs/router/client";
|
|
267
406
|
|
|
268
407
|
function BreadcrumbNav() {
|
|
269
408
|
const crumbs = useHandle(Breadcrumbs);
|
|
@@ -294,11 +433,12 @@ path("/dashboard", (ctx) => {
|
|
|
294
433
|
push({ label: "Dashboard", href: "/dashboard" });
|
|
295
434
|
return <DashboardNav handle={Breadcrumbs} />;
|
|
296
435
|
});
|
|
436
|
+
```
|
|
297
437
|
|
|
438
|
+
```tsx
|
|
298
439
|
// Client component — typeof infers the full Handle<T> type
|
|
299
|
-
|
|
300
|
-
import { useHandle } from "@rangojs/router/client";
|
|
301
|
-
import type { Breadcrumbs } from "../handles";
|
|
440
|
+
"use client";
|
|
441
|
+
import { useHandle, type Breadcrumbs } from "@rangojs/router/client";
|
|
302
442
|
|
|
303
443
|
function DashboardNav({ handle }: { handle: typeof Breadcrumbs }) {
|
|
304
444
|
const crumbs = useHandle(handle);
|
|
@@ -318,13 +458,18 @@ RSC serialization strips the `collect` function via `toJSON()`. On the client,
|
|
|
318
458
|
|
|
319
459
|
## Action Hooks
|
|
320
460
|
|
|
461
|
+
For the full server-action guide (defining actions, `useActionState`,
|
|
462
|
+
`useOptimistic`, validation, revalidation, error handling, file uploads),
|
|
463
|
+
see `/server-actions`. `useAction()` below is a Rango-specific hook for
|
|
464
|
+
tracking actions called outside a `<form action={...}>` flow.
|
|
465
|
+
|
|
321
466
|
### useAction()
|
|
322
467
|
|
|
323
468
|
Track state of server action invocations:
|
|
324
469
|
|
|
325
470
|
```tsx
|
|
326
471
|
"use client";
|
|
327
|
-
import { useAction } from "@rangojs/router";
|
|
472
|
+
import { useAction } from "@rangojs/router/client";
|
|
328
473
|
import { addToCart } from "../actions/cart";
|
|
329
474
|
|
|
330
475
|
function AddToCartButton({ productId }: { productId: string }) {
|
|
@@ -359,7 +504,7 @@ Read type-safe state from history:
|
|
|
359
504
|
|
|
360
505
|
```tsx
|
|
361
506
|
"use client";
|
|
362
|
-
import { useLocationState, createLocationState } from "@rangojs/router";
|
|
507
|
+
import { useLocationState, createLocationState } from "@rangojs/router/client";
|
|
363
508
|
|
|
364
509
|
// Define typed state (all export patterns supported)
|
|
365
510
|
// Keys are auto-injected by the Vite plugin -- no manual key needed.
|
|
@@ -501,33 +646,81 @@ const flash = FlashMessage.read();
|
|
|
501
646
|
const product = ProductState.read();
|
|
502
647
|
```
|
|
503
648
|
|
|
504
|
-
|
|
649
|
+
> **Hydration:** `.read()` returns `undefined` on the server but may return
|
|
650
|
+
> a real value on the first client render (history state survives reload).
|
|
651
|
+
> Do not call `.read()` directly during the initial render of a component;
|
|
652
|
+
> call it from an event handler or inside a `useEffect` post-mount. For
|
|
653
|
+
> reactive hydration-safe access, use `useLocationState()` instead.
|
|
654
|
+
|
|
655
|
+
### .write() / .delete() (static, non-reactive)
|
|
505
656
|
|
|
506
|
-
|
|
657
|
+
Static counterparts to `.read()`. Both mutate the current history entry's
|
|
658
|
+
`history.state` via `replaceState`, preserving any other keys (router
|
|
659
|
+
bookkeeping, other location state slots). Both are client-only; they throw
|
|
660
|
+
when called on the server.
|
|
507
661
|
|
|
508
|
-
|
|
662
|
+
Neither dispatches an event, so components reading via `useLocationState`
|
|
663
|
+
will NOT re-render until the next navigation/popstate. Pair with `.read()`
|
|
664
|
+
(or a fresh mount via back/forward/reload) instead.
|
|
509
665
|
|
|
510
666
|
```tsx
|
|
511
667
|
"use client";
|
|
512
|
-
import {
|
|
668
|
+
import { ProductState } from "./state";
|
|
513
669
|
|
|
514
|
-
|
|
515
|
-
|
|
670
|
+
// Persisted across hard refresh and back/forward of this entry.
|
|
671
|
+
ProductState.write({ name: "Widget", price: 9.99 });
|
|
672
|
+
|
|
673
|
+
// Read later (or on next mount).
|
|
674
|
+
const current = ProductState.read();
|
|
675
|
+
|
|
676
|
+
// Manually clear the slot. Idempotent if it isn't set.
|
|
677
|
+
ProductState.delete();
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
| Method | Updates `history.state` | Fires `useLocationState` rerender | SSR behavior |
|
|
681
|
+
| ----------- | ----------------------- | --------------------------------- | ------------------- |
|
|
682
|
+
| `.read()` | no | n/a (returns snapshot) | returns `undefined` |
|
|
683
|
+
| `.write()` | yes (replace this slot) | no | throws |
|
|
684
|
+
| `.delete()` | yes (remove this slot) | no | throws |
|
|
685
|
+
|
|
686
|
+
## Cache Control
|
|
687
|
+
|
|
688
|
+
### invalidateClientCache()
|
|
689
|
+
|
|
690
|
+
Force the client's caches to miss after a mutation the router can't see (a REST
|
|
691
|
+
call, a WebSocket push, a login). It is a plain function, not a hook, so it works
|
|
692
|
+
from module-level callbacks too. Imported from the root entry `@rangojs/router`,
|
|
693
|
+
it is selected by export conditions: in a client component it marks the caches
|
|
694
|
+
stale immediately; from a handler/server component it writes a rotated
|
|
695
|
+
`Set-Cookie` for the responding client.
|
|
516
696
|
|
|
697
|
+
```tsx
|
|
698
|
+
"use client";
|
|
699
|
+
import { invalidateClientCache } from "@rangojs/router";
|
|
700
|
+
|
|
701
|
+
function SaveButton() {
|
|
517
702
|
const handleSave = async () => {
|
|
518
703
|
await fetch("/api/data", {
|
|
519
704
|
method: "POST",
|
|
520
705
|
body: JSON.stringify(data),
|
|
521
706
|
});
|
|
522
707
|
|
|
523
|
-
// Invalidate
|
|
524
|
-
|
|
708
|
+
// Invalidate the client's caches after the mutation
|
|
709
|
+
invalidateClientCache();
|
|
525
710
|
};
|
|
526
711
|
|
|
527
712
|
return <button onClick={handleSave}>Save</button>;
|
|
528
713
|
}
|
|
529
714
|
```
|
|
530
715
|
|
|
716
|
+
A module-level subscription works the same way (no component needed):
|
|
717
|
+
|
|
718
|
+
```ts
|
|
719
|
+
import { invalidateClientCache } from "@rangojs/router";
|
|
720
|
+
|
|
721
|
+
socket.on("catalog-updated", () => invalidateClientCache());
|
|
722
|
+
```
|
|
723
|
+
|
|
531
724
|
**Use cases**: REST API mutations, WebSocket updates, non-RSC data changes.
|
|
532
725
|
|
|
533
726
|
## Outlet Components
|
|
@@ -537,7 +730,7 @@ function SaveButton() {
|
|
|
537
730
|
Render child content in layouts:
|
|
538
731
|
|
|
539
732
|
```tsx
|
|
540
|
-
import { Outlet, ParallelOutlet } from "@rangojs/router";
|
|
733
|
+
import { Outlet, ParallelOutlet } from "@rangojs/router/client";
|
|
541
734
|
|
|
542
735
|
function DashboardLayout({ children }: { children?: React.ReactNode }) {
|
|
543
736
|
return (
|
|
@@ -558,7 +751,7 @@ Access outlet content programmatically:
|
|
|
558
751
|
|
|
559
752
|
```tsx
|
|
560
753
|
"use client";
|
|
561
|
-
import { useOutlet } from "@rangojs/router";
|
|
754
|
+
import { useOutlet } from "@rangojs/router/client";
|
|
562
755
|
|
|
563
756
|
function ConditionalLayout() {
|
|
564
757
|
const outlet = useOutlet();
|
|
@@ -590,6 +783,12 @@ function ProductPage() {
|
|
|
590
783
|
return <h1>Product {params.productId}</h1>;
|
|
591
784
|
}
|
|
592
785
|
|
|
786
|
+
// Annotate the expected shape via a generic
|
|
787
|
+
function ProductPageTyped() {
|
|
788
|
+
const { productId } = useParams<{ productId: string }>();
|
|
789
|
+
return <h1>Product {productId}</h1>;
|
|
790
|
+
}
|
|
791
|
+
|
|
593
792
|
// With selector for performance (re-renders only when selected value changes)
|
|
594
793
|
function ProductId() {
|
|
595
794
|
const productId = useParams((p) => p.productId);
|
|
@@ -597,7 +796,7 @@ function ProductId() {
|
|
|
597
796
|
}
|
|
598
797
|
```
|
|
599
798
|
|
|
600
|
-
Returns merged params from all matched route segments. Updates on navigation commit (not during pending navigation).
|
|
799
|
+
Returns merged params from all matched route segments as a `Readonly<T>` map. Updates on navigation commit (not during pending navigation).
|
|
601
800
|
|
|
602
801
|
### usePathname()
|
|
603
802
|
|
|
@@ -678,25 +877,48 @@ function MountInfo() {
|
|
|
678
877
|
}
|
|
679
878
|
```
|
|
680
879
|
|
|
681
|
-
|
|
880
|
+
### useReverse(routes)
|
|
881
|
+
|
|
882
|
+
Mount-aware local reverse for client components. Import the generated `routes` map from a `urls()` module's `.gen.ts` and call `reverse("name", params?)` — the leading dot is optional. Auto-fills params from `useParams()`; explicit params override.
|
|
883
|
+
|
|
884
|
+
> Per-module `*.gen.ts` files are **CLI opt-in and not Vite-watched** — run `rango generate <urls-file>` (or wire it into `predev`) and re-run it whenever the module's routes change. See `/links` for the full generated-file setup and exposure-boundary rules.
|
|
885
|
+
|
|
886
|
+
```tsx
|
|
887
|
+
"use client";
|
|
888
|
+
import { Link, useReverse } from "@rangojs/router/client";
|
|
889
|
+
import { routes as blogRoutes } from "../urls/blog.gen.js";
|
|
890
|
+
|
|
891
|
+
function BlogNav() {
|
|
892
|
+
const reverse = useReverse(blogRoutes);
|
|
893
|
+
return (
|
|
894
|
+
<nav>
|
|
895
|
+
<Link to={reverse("index")}>Blog</Link>
|
|
896
|
+
<Link to={reverse("post", { postId: "hello" })}>Post</Link>
|
|
897
|
+
</nav>
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
See `/links` for the full URL generation guide. `ctx.reverse()` is server-only; on the client, prefer `useReverse(routes)` for in-module names and pass URLs as props for cross-module ones.
|
|
682
903
|
|
|
683
904
|
## Hook Summary
|
|
684
905
|
|
|
685
|
-
| Hook
|
|
686
|
-
|
|
|
687
|
-
| `useParams()`
|
|
688
|
-
| `usePathname()`
|
|
689
|
-
| `useSearchParams()`
|
|
690
|
-
| `useHref()`
|
|
691
|
-
| `useMount()`
|
|
692
|
-
| `
|
|
693
|
-
| `
|
|
694
|
-
| `
|
|
695
|
-
| `
|
|
696
|
-
| `
|
|
697
|
-
| `
|
|
698
|
-
| `
|
|
699
|
-
| `
|
|
700
|
-
| `
|
|
701
|
-
| `
|
|
702
|
-
| `
|
|
906
|
+
| Hook | Purpose | Returns |
|
|
907
|
+
| ------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
908
|
+
| `useParams()` | Route params | `Readonly<T>` (default `Record<string, string>`) or selected value |
|
|
909
|
+
| `usePathname()` | Current pathname | `string` |
|
|
910
|
+
| `useSearchParams()` | URL search params | `ReadonlyURLSearchParams` |
|
|
911
|
+
| `useHref()` | Mount-aware href | `(path) => string` |
|
|
912
|
+
| `useMount()` | Current include() mount path | `string` |
|
|
913
|
+
| `useReverse()` | Local reverse for imported routes | `(name, params?, search?) => string` |
|
|
914
|
+
| `useNavigation()` | Reactive navigation state | state, location, isStreaming |
|
|
915
|
+
| `useRouter()` | Stable router actions | push, replace, refresh, prefetch, back, forward |
|
|
916
|
+
| `useSegments()` | URL path & segment IDs | path, segmentIds, location |
|
|
917
|
+
| `useLinkStatus()` | Link pending state | { pending } |
|
|
918
|
+
| `useLoader()` | Loader data (strict) | data, isLoading, error, load, refetch |
|
|
919
|
+
| `useFetchLoader()` | Loader with on-demand fetch | data, load, isLoading, error, refetch |
|
|
920
|
+
| `useRefreshLoaders()` | Refresh cross-loader group(s) | `() => (groups: string \| string[]) => Promise<void>` |
|
|
921
|
+
| `useHandle()` | Accumulated handle data | T (handle type) |
|
|
922
|
+
| `useAction()` | Server action state | state, error, result |
|
|
923
|
+
| `useLocationState()` | History state (persists or flash) | T \| undefined |
|
|
924
|
+
| `invalidateClientCache()` | Force client caches to miss (function, not a hook; root entry) | `void` |
|