@rpcbase/router
v0.148.0
Published
`loadRoute` has been removed. Use `lazyRoute` everywhere.
Downloads
5,072
Readme
@rpcbase/router
lazyRoute (replacement for loadRoute)
loadRoute has been removed.
Use lazyRoute everywhere.
Migration (drop-in)
Before:
import { Route, loadRoute } from "@rpcbase/router"
const homePageRoute = loadRoute(import("@/pages/HomePage"))
<Route path="/" {...homePageRoute} />After:
import { Route, lazyRoute } from "@rpcbase/router"
const homePageRoute = lazyRoute(() => import("@/pages/HomePage"))
<Route path="/" {...homePageRoute} />Route module contract
A lazy route module should export:
default: React componentloader(optional): route loader
export default function HomePage() {
return <h1>Home</h1>
}
export const loader = async ({ ctx }) => {
return { user: ctx.req.session?.user ?? null }
}Promise behavior (important)
Use a function that returns the import promise:
lazyRoute(() => import("@/pages/HomePage"))Do not pass an already-started promise:
lazyRoute(import("@/pages/HomePage"))Why:
() => import(...)delays loading until route lazy resolution/prefetch.- The importer is memoized, so concurrent lazy/load/prefetch calls share the same promise.
Optional prefetch data flag
Code prefetch can happen without data prefetch by default.
If you want route data prefetch for a route, set prefetchData: true:
const reportsRoute = lazyRoute(() => import("@/pages/ReportsPage"), {
prefetchData: true,
})Query-driven overlays
Use useQueryOverlay to drive modal/drawer/sheet state from one or more query params.
import { QueryOverlay, useQueryOverlay } from "@rpcbase/router"
type SupportOverlay = "support" | "feedback"
const isSupportOverlay = (value: string | null): value is SupportOverlay =>
value === "support" || value === "feedback"
function useSupportOverlay() {
return useQueryOverlay<SupportOverlay>({
params: ["modal"],
parse: (params) => {
const value = params.get("modal")
return isSupportOverlay(value) ? value : null
},
write: (params, value) => {
params.set("modal", value)
},
clear: (params) => {
params.delete("modal")
},
})
}
function SupportModalOverlay() {
const overlay = useSupportOverlay()
return (
<QueryOverlay
overlay={overlay}
errorFallback={<SupportModalError />}
>
{(state, controls) => (
<SupportModal
open={controls.open}
onOpenChange={controls.setOpen}
kind={state}
/>
)}
</QueryOverlay>
)
}When lazy overlay content suspends, QueryOverlay renders a neutral fullscreen backdrop with a centered loading indicator by default. Pass fallback={null} to opt out, or pass a custom fallback when an overlay needs a different loading state.
Returned API:
value: parsed value from the query params (T | null)isOpen:truewhen the overlay is visually openshouldRender:truewhile the overlay should stay mountedbuildHref(nextValue): builds next URL for links/prefetchopenOverlay(nextValue): clears the overlay params, writes the next state, and replaces the current URLcloseOverlay(): visually closes immediately, then clears the overlay params immediately or aftercloseDelayMswhen configuredresetOptimisticClose(): cancels a pending optimistic close
Overlay query updates use history.replaceState instead of a router navigation. This keeps the URL shareable without forcing the current route tree to re-render when only an overlay param changes.
During SSR and hydration, useQueryOverlay reads the current React Router location so query-driven overlays can render in their initial server state.
Shortcut prefetch + navigate
Use useShortcutPrefetchNavigate to prefetch on keydown and navigate on keyup.
This avoids losing pending shortcut state across rerenders.
import { useRoutePrefetch, useShortcutPrefetchNavigate } from "@rpcbase/router"
function SupportShortcut({ getHref }: { getHref: () => string }) {
const { prefetch } = useRoutePrefetch()
useShortcutPrefetchNavigate({
shortcut: { key: "k", mod: true },
trigger: "keyup",
getHref,
prefetch,
})
return null
}Default behavior:
- Ignores shortcuts while typing in
input,textarea,select, or content editable - Calls
event.preventDefault() - Resets pending keyup state on window blur
- Uses router navigation if
navigateis not provided
