Link - greydragon888/real-router GitHub Wiki

Link

1. Overview

  • Name: Link
  • Purpose: High-level navigation link component that automatically gets router from context
  • When to use: For creating navigation links in components inside RouterProvider

2. Import and Basic Usage

import { Link } from "@real-router/react";
// or
import { Link } from "@real-router/preact";
// or
import { Link } from "@real-router/solid";
// or
import { Link } from "@real-router/vue";
// or
import { Link } from "@real-router/svelte";

// Angular (directive, not component)
import { RealLink } from "@real-router/angular";
// Used as: <a realLink routeName="home">Home</a>

function Navigation() {
  return (
    <nav>
      <Link routeName="home">Home</Link>
      <Link routeName="users">Users</Link>
      <Link routeName="users.profile" routeParams={{ id: "123" }}>
        Profile
      </Link>
    </nav>
  );
}

3. Props

Prop Type Required Default Description
routeName string Yes Target route name
routeParams Params No {} Route parameters
routeOptions NavigationOptions No {} Navigation options (e.g. { replace: true })
className string No CSS class
activeClassName string No "active" CSS class for active state
activeStrict boolean No false Strict activity check
ignoreQueryParams boolean No true Ignore query params
onClick MouseEventHandler No Custom click handler
onMouseOver MouseEventHandler No Mouse over handler
target string No HTML target attribute
children ReactNode No Link content

Note: Link gets router automatically from RouterProvider context. All navigation props including routeOptions are supported directly.

4. Children

  • Type: ReactNode
  • Description: Link content — text, icons, components
<Link routeName="dashboard">
  <DashboardIcon />
  <span>Dashboard</span>
</Link>

5. Rendering

What It Renders

  • HTML element: <a>
  • Attributes: href, className, onClick
<a href="/users/123" class="nav-link active"> User Profile </a>

6. Styling

CSS Classes

Class Condition Description
className Always Base CSS class
activeClassName Route is active Default is "active"

Examples

<Link routeName="home" className="nav-link" activeClassName="nav-link--current">
  Home
</Link>
.nav-link {
  color: #666;
  text-decoration: none;
}

.nav-link--current {
  color: #000;
  font-weight: bold;
}

7. Accessibility

  • Semantics: Native <a> element with correct href
  • Keyboard: Tab for focus, Enter for navigation
  • Screen readers: Read as standard link

8. Dependencies and Context

Required Providers

Provider Required Description
RouterProvider Yes For getting router via useRouter

Used Hooks

  • useRouter — getting router instance from context

9. Events

Event Signature Description
onClick MouseEventHandler<HTMLAnchorElement> Link click
onMouseOver MouseEventHandler<HTMLAnchorElement> Mouse hover

10. Behavior

Main Scenarios

  • Renders <a> element with correct href
  • Does not have active class if route is inactive
  • Adds active class if route is active
  • Works with router's default route

Edge Cases

  • Works correctly when router not started (href is generated)
  • Works with defaultRoute router option

Guarantees

  • Automatic router retrieval from context
  • Memoized rendering — only re-renders when active state or props change

11. Related Components

Component/Hook Relationship
useRouter Used for getting router
RouterProvider Required provider

11.1. See Also: Directive Alternatives

For applying navigation to any element without using Link, framework-specific directives are available:

  • Solid: use:link directive
  • Vue: v-link directive
  • Svelte: createLinkAction factory
  • Angular: realLink directive on <a> elements, [realLinkActive] for active class on any element

These provide low-level navigation control for custom elements.

Angular note: Angular uses the realLink directive on <a> elements instead of a <Link> component. Inputs: routeName, routeParams, routeOptions, activeClassName, activeStrict, ignoreQueryParams. The directive also checks target="_blank" and skips client-side navigation for external links.

12. Usage Examples

Basic Example

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

function Navigation() {
  return (
    <nav>
      <Link routeName="home">Home</Link>
      <Link routeName="about">About</Link>
      <Link routeName="contact">Contact</Link>
    </nav>
  );
}

With Route Parameters

function UsersList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>
          <Link routeName="users.profile" routeParams={{ id: user.id }}>
            {user.name}
          </Link>
        </li>
      ))}
    </ul>
  );
}

Custom Active State Styling

function MainNav() {
  return (
    <nav className="main-nav">
      <Link
        routeName="dashboard"
        className="main-nav__link"
        activeClassName="main-nav__link--active"
      >
        Dashboard
      </Link>
      <Link
        routeName="settings"
        className="main-nav__link"
        activeClassName="main-nav__link--active"
      >
        Settings
      </Link>
    </nav>
  );
}

Strict Activity Check

function SectionNav() {
  return (
    <nav>
      {/* Active for /users, /users/list, /users/123 */}
      <Link routeName="users" activeStrict={false}>
        All Users
      </Link>

      {/* Active ONLY for /users */}
      <Link routeName="users" activeStrict={true}>
        Users Index
      </Link>
    </nav>
  );
}

With Event Handling

function TrackedLink({ routeName, children }) {
  return (
    <Link
      routeName={routeName}
      onClick={() => {
        analytics.track("link_clicked", { route: routeName });
      }}
    >
      {children}
    </Link>
  );
}

Tip: To handle navigation results (success/error), call router.navigate() directly instead of using Link. The navigate() method returns a Promise<State>.

Anti-patterns

// Don't use Link outside RouterProvider
function Bad() {
  return <Link routeName="home">Home</Link>; // Error!
}

// Wrap in RouterProvider
function Good() {
  return (
    <RouterProvider router={router}>
      <Link routeName="home">Home</Link>
    </RouterProvider>
  );
}
// Don't use for external URLs
function Bad() {
  return <Link routeName="https://google.com">Google</Link>;
}

// Use regular <a> for external links
function Good() {
  return (
    <a href="https://google.com" target="_blank" rel="noopener">
      Google
    </a>
  );
}
// Don't pass router — it's ignored
function Bad() {
  const myRouter = useRouter();
  return (
    <Link router={myRouter} routeName="home">
      Home
    </Link>
  );
}

// Link gets router automatically
function Good() {
  return <Link routeName="home">Home</Link>;
}
// routeOptions supported directly on Link
function ReplaceNavigation() {
  return (
    <Link routeName="checkout" routeOptions={{ replace: true }}>
      Checkout
    </Link>
  );
}

13. Migration from router5

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

Version Comparison

router5 (react-router5) Real Router (@real-router/react)
Implementation withRouter(BaseLink) (HOC) Function Component with useRouter()
Export Named Named
Router retrieval routerContext.Consumer (render prop) useRouter() hook

1. Breaking Changes

Severity What Changed Was Now Impact
LOW Internal implementation HOC withRouter(BaseLink) FC with useRouter() No API impact
LOW successCallback Prop on link Removed Use router.navigate() promise instead
LOW errorCallback Prop on link Removed Use router.navigate() promise instead

Props Changes

Props remain compatible:

Prop Was Now Change
routeName Yes Yes No change
routeParams Yes Yes No change
routeOptions Yes Yes No change
className Yes Yes No change
activeClassName Yes Yes No change
activeStrict Yes Yes No change
ignoreQueryParams Yes Yes No change
onClick Yes Yes No change
successCallback Yes No Removed
errorCallback Yes No Removed

Examples

// routeOptions works directly on Link (no change needed from router5)
<Link routeName="checkout" routeOptions={{ replace: true }}>
  Checkout
</Link>

2. Implementation Changes

Architecture

  • Was: HOC pattern — withRouter(BaseLink) creates component that gets router via routerContext.Consumer
  • Now: Hook pattern — Link uses useRouter() and passes to BaseLink

Advantages of New Approach

  • Simpler code: No intermediate HOC layer
  • Better typing: TypeScript works better with hooks than HOC
  • Fewer nesting levels: Simpler structure in DevTools
  • Modern React: Uses hooks instead of render props/HOC

Removed Components

  • withRouter HOC: No longer needed — use useRouter() hook directly
  • ConnectedLink: Was withRoute(BaseLink) — use Link + useRoute() instead
  • BaseLink: Merged into Link — all props including routeOptions are supported directly

3. Dependency Changes

Dependency Was Now
Router package router5 @real-router/core
React bindings react-router5 @real-router/react
Pattern HOC (withRouter) Hook (useRouter)

4. Migration Guide

Checklist

  • Update package import from react-router5 to @real-router/react
  • routeOptions works on Link directly — no changes needed
  • If successCallback/errorCallback was used — use router.navigate() which returns Promise<State>
  • If withRouter HOC was used — replace with useRouter() hook
  • If ConnectedLink was used — replace with Link or custom component with useRoute()
  • If BaseLink was used — replace with Link inside RouterProvider

Step-by-Step Migration

  1. Update imports: Replace react-router5 with @real-router/react
  2. routeOptions: Works on Link directly — no migration needed
  3. Replace callbacks: If successCallback/errorCallback was used — call router.navigate() directly and handle the returned Promise<State>
  4. Replace HOC: withRouteruseRouter() hook
  5. Remove ConnectedLink: Use Link or create custom component with useRoute()
  6. Remove BaseLink: Use Link inside RouterProvider — all props supported directly

5. Summary

Category Status
Breaking Changes LOW (successCallback, errorCallback removed)
New props None
Removed props successCallback/errorCallback
Behavior changes Navigation results via router.navigate() promise
Optimizations Hooks instead of HOC

Maximum severity: LOW — successCallback/errorCallback removed in favor of router.navigate() returning Promise<State>. routeOptions is supported directly on Link.

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