useRouter
The useRouter hook provides access to navigation methods for programmatic routing. It returns an object with push and replace methods to navigate between routes.
import { useRouter } from "@toapi/router";
function LoginForm() { const router = useRouter();
const handleLogin = async (credentials) => { try { await login(credentials); router.push("/dashboard"); } catch (error) { console.error("Login failed:", error); } };
return ( <form onSubmit={handleLogin}> {/* form fields */} </form> );}Return Value
Section titled “Return Value”The hook returns an object with the following methods:
push(url: string, options?: { useTransition?: boolean | ((scope: () => void) => void) })
Section titled “push(url: string, options?: { useTransition?: boolean | ((scope: () => void) => void) })”- Description: navigate to a new route by adding a new entry to the browser’s history stack
- Parameters:
url(string): the destination URL (absolute path, relative path, or full URL with query parameters)options.useTransition(optional): controls how the resulting state update is scheduled.undefined(default): wrapped in React’sstartTransition.false: applied synchronously, outside of a transition.- a function: called with the update, so you can supply your own transition (e.g. the
startTransitionfrom React’suseTransition()hook).
- Returns:
void
const router = useRouter();
// Navigate to absolute pathrouter.push("/users");
// Navigate with parametersrouter.push("/users/123");
// Navigate with query parametersrouter.push("/search?q=react");
// Navigate with hashrouter.push("/docs#installation");
// Navigate with everythingrouter.push("/products?category=electronics&sort=price#top");
// Navigate synchronously, without a transitionrouter.push("/checkout", { useTransition: false });replace(url: string, options?: { useTransition?: boolean | ((scope: () => void) => void) })
Section titled “replace(url: string, options?: { useTransition?: boolean | ((scope: () => void) => void) })”- Description: navigate to a new route by replacing the current entry in the browser’s history stack
- Parameters:
url(string): the destination URL (absolute path, relative path, or full URL with query parameters)options.useTransition(optional): same aspush’soptions.useTransition.
- Returns:
void
const router = useRouter();
// Replace current history entryrouter.replace("/login");
// Useful for redirects where you don't want users to go backrouter.replace("/dashboard");Context-Aware Resolution
Section titled “Context-Aware Resolution”Like Link, useRouter resolves the URL you pass relative to the current route context. Absolute paths (starting with /) navigate exactly; relative paths resolve against the matched parent route; and query-only (?…) or hash-only (#…) hrefs are appended to the current location.
// Inside a route matched at /users/123const router = useRouter();router.push("edit"); // -> /users/123/editrouter.push("?tab=bio"); // -> /users/123?tab=biorouter.push("/"); // -> /Navigation Methods Comparison
Section titled “Navigation Methods Comparison”| Method | History Stack | Use Case |
|---|---|---|
push |
Adds new entry | Normal navigation, allows the back button |
replace |
Replaces current entry | Redirects, login flows, error corrections |
Examples
Section titled “Examples”Navigating Without a Transition
Section titled “Navigating Without a Transition”Pass useTransition: false when a caller needs the pathname/search state to update synchronously, right after push/replace returns:
function CheckoutButton() { const router = useRouter();
return ( <button onClick={() => { router.push("/checkout", { useTransition: false }); }} > Checkout </button> );}Showing a Loading State with useTransition
Section titled “Showing a Loading State with useTransition”Pass React’s startTransition (from the useTransition() hook) as options.useTransition to get an isPending flag for the duration of the navigation:
import { useTransition } from "react";import { useRouter } from "@toapi/router";
function DashboardLink() { const router = useRouter(); const [isPending, startTransition] = useTransition();
return ( <button disabled={isPending} onClick={() => { router.push("/dashboard", { useTransition: startTransition }); }} > {isPending ? "Loading…" : "Go to Dashboard"} </button> );}Combining with useOptimistic
Section titled “Combining with useOptimistic”useOptimistic updates must happen inside a transition. Wrap the whole handler — the optimistic update and the navigation — in startTransition yourself, and pass useTransition: false to push/replace so it doesn’t start a second, nested transition:
import { startTransition, useOptimistic } from "react";import { useRouter } from "@toapi/router";
function ArchiveButton({ itemId, onArchive }) { const router = useRouter(); const [isArchived, setOptimisticArchived] = useOptimistic(false);
return ( <button onClick={() => { startTransition(() => { setOptimisticArchived(true); onArchive(itemId); router.push("/items", { useTransition: false }); }); }} > {isArchived ? "Archiving…" : "Archive"} </button> );}Related
Section titled “Related”- Link — declarative navigation as an anchor element
- usePathname — access the current pathname
- useParams — access route parameters
- useSearchParams — access search parameters