useRouter - greydragon888/real-router GitHub Wiki

useRouter

1. Overview

  • Name: useRouter
  • Purpose: Get router instance for navigation and other operations without subscribing to state changes
  • When to use: When a component only needs access to router methods (navigate, stop, start, etc.) without needing to react to route changes

2. Signature

function useRouter(): Router;
import { useRouter } from "@real-router/react";
// or
import { useRouter } from "@real-router/preact";
// or
import { useRouter } from "@real-router/solid";
// or
import { useRouter } from "@real-router/vue";
// or
import { useRouter } from "@real-router/svelte";

// Angular
import { injectRouter } from "@real-router/angular";

Angular note: injectRouter() must be called within an injection context (constructor or field initializer). Returns the Router instance directly -- not a signal.

Basic Example

function MyComponent() {
  const router = useRouter();

  const handleClick = () => {
    router.navigate("users.profile", { id: "123" });
  };

  return <button onClick={handleClick}>Go to Profile</button>;
}

3. Parameters

Hook accepts no parameters.

4. Return Value

  • Type: Router
  • Description: Router instance from @real-router/core

Main Router Methods

Method Description
navigate(name, params?, options?) Navigate to route
start() Start router
stop() Stop router
subscribe(listener) Subscribe to changes (low-level)
subscribeLeave(listener) Subscribe to confirmed departures
isLeaveApproved() True in LEAVE_APPROVED phase
getState() Get current state
buildPath(name, params?) Build URL for route
isActive(name, params?, options?) Check if route is active

5. Dependencies and Context

Required Providers

Provider Required Description
RouterProvider Yes Must wrap the component using the hook

Used Hooks

  • useContext(RouterContext) — getting router instance from context

6. Re-render Behavior

  • Reference stability: router — stable reference, doesn't change between renders
  • Update triggers: Hook does NOT cause re-renders on navigation
  • Memoization: Not required — return value is already stable

Important: Unlike useRoute, the useRouter hook does not subscribe to router state changes. A component using only useRouter will not re-render on navigation.

7. Possible Errors

Condition Error How to Avoid
Hook called outside RouterProvider "useRouter must be used within a RouterProvider" Wrap component in RouterProvider

8. Behavior

Main Scenarios

  • Returns the same router instance passed to RouterProvider
  • Throws error when provider is missing

Edge Cases

  • Router doesn't need to be started (start()) for hook to work

Guarantees

  • Hook returns referentially stable router instance
  • Fail-fast behavior when provider is missing

9. Related Hooks

Hook When to Use Instead
useRoute When you need current route access and automatic re-renders on navigation
useRouteNode When you need subscription only to specific route node

10. Usage Examples

Basic Example — Button Navigation

import { useRouter } from "@real-router/react";

function LogoutButton() {
  const router = useRouter();

  const handleLogout = async () => {
    await api.logout();
    router.navigate("auth.login");
  };

  return <button onClick={handleLogout}>Logout</button>;
}

Building URL Without Navigation

function ShareButton({ routeName, params }) {
  const router = useRouter();

  const url = router.buildPath(routeName, params);

  const handleShare = () => {
    navigator.clipboard.writeText(window.location.origin + url);
  };

  return <button onClick={handleShare}>Copy Link</button>;
}

Programmatic Navigation with Options

function FormComponent() {
  const router = useRouter();

  const handleSubmit = async (data) => {
    await api.saveData(data);

    // replace: true — doesn't add entry to history
    router.navigate("success", {}, { replace: true });
  };

  return <form onSubmit={handleSubmit}>...</form>;
}

Auto-Save on Confirmed Departure

function EditorComponent() {
  const router = useRouter();

  useEffect(() => {
    // Auto-save form draft when leaving (only if departure confirmed)
    const unsub = router.subscribeLeave(({ route }) => {
      if (route.name === "editor") {
        localStorage.setItem("editor:draft", getEditorContent());
      }
    });

    return unsub;
  }, [router]);

  return <textarea placeholder="Edit content..." />;
}

Anti-patterns

// Don't use useRouter to get current route
function Bad() {
  const router = useRouter();
  const state = router.getState(); // Not reactive! Component won't update on navigation
  return <div>{state?.name}</div>;
}

// Use useRoute for reactive route access
function Good() {
  const { route } = useRoute();
  return <div>{route?.name}</div>;
}
// Don't subscribe manually via router.subscribe
function Bad() {
  const router = useRouter();
  const [route, setRoute] = useState(router.getState());

  useEffect(() => {
    return router.subscribe(({ route }) => setRoute(route));
  }, [router]);

  return <div>{route?.name}</div>;
}

// Use useRoute — it already does this correctly
function Good() {
  const { route } = useRoute();
  return <div>{route?.name}</div>;
}
// Don't pass router via props to deep components
function Bad() {
  const router = useRouter();
  return <DeepChild router={router} />;
}

// Use useRouter in child component
function Good() {
  return <DeepChild />; // DeepChild will call useRouter() itself
}

11. Migration from router5

Comparison of @real-router/react/useRouter with react-router5/useRouter from router5.

Version Comparison

router5 (react-router5) Real Router (@real-router/react)
Export export default function useRouter() export const useRouter
Signature useRouter(): Router useRouter(): Router
Router type router5.Router @real-router/core Router

1. Breaking Changes

Severity What Changed Was Now Impact
CRITICAL Export type export default export const (named) All imports will break
HIGH Context validation Returns undefined if no provider Throws Error Code without provider will crash
MEDIUM Router type router5.Router @real-router/core Router API may differ

Parameter Changes

Hook accepts no parameters — no changes.

Return Value Changes

Field Change Migration
Router type router5.Router@real-router/core Router Check router API compatibility

Examples

// Code that will break (import)
import useRouter from "react-router5";

// Code after migration
import { useRouter } from "@real-router/react";
// Code that will break (without provider)
function Orphan() {
  const router = useRouter(); // Previously returned undefined
  router?.navigate("home"); // Worked with optional chaining
}

// Code after migration — ensure provider exists
// Now throws error: "useRouter must be used within a RouterProvider"

2. Implementation Changes

New Behavior

  • Fail-fast validation: Hook now throws clear error "useRouter must be used within a RouterProvider" if called outside provider. Previously returned undefined, causing implicit errors later.

Context Changes

  • Context name: routerContextRouterContext (internal detail, doesn't affect users)

3. Dependency Changes

Dependency Was Now
Router package router5 @real-router/core
React bindings react-router5 @real-router/react

4. Migration Guide

Checklist

  • Replace import useRouter from 'react-router5' with import { useRouter } from '@real-router/react'
  • Ensure all components with useRouter are wrapped in RouterProvider
  • Remove optional chaining when calling router methods (no longer needed — router is always defined)
  • Check compatibility with new @real-router/core API

Step-by-Step Migration

  1. Update imports: Replace default import with named import
  2. Check providers: Ensure all components with useRouter are inside RouterProvider
  3. Simplify code: Remove unnecessary undefined checks — router is now always defined
  4. Check API: Ensure used router methods are compatible with @real-router/core

5. Summary

Category Status
Breaking Changes CRITICAL (export)
New parameters None
Removed parameters None
Behavior changes Fail-fast validation
Optimizations None

Maximum severity: CRITICAL — all import changes required

⚠️ **GitHub.com Fallback** ⚠️