routerEdit this page

Client-side navigation

After the server has rendered the initial page, the client takes over and handles all subsequent navigation. This can be done by using the client components exported by the @lazarv/react-server/navigation module or by the functions exposed by the useClient hook from the @lazarv/react-server/client module. You can use these functions to navigate to a new page, prefetch a page, or refresh the current page.

It's recommended to use the built-in client components for navigation and refresh. These components will automatically start a React transition to render only the parts of the page that are changing. This will improve the user experience by reducing the amount of time the user has to wait for the page to load.

Functions exposed by the useClient hook are more low-level and should be used only when you need to start a React transition manually.

You can navigate to a new page by using the Link client component exported by the @lazarv/react-server/navigation module.

import { Link } from "@lazarv/react-server/navigation";

export default function Home() {
  return (
    <div>
      <Link to="/about">About</Link>
    </div>
  );
}

You can enable prefetching of the page by passing the prefetch prop to the Link component. This will prefetch the page when the user hovers over the link.

import { Link } from "@lazarv/react-server/client";

export default function Home() {
  return (
    <div>
      <Link to="/about" prefetch>
        About
      </Link>
    </div>
  );
}

By default, the prefetched page will be cached indefinitely. You can change this behavior by passing the timeout value in the prefetch prop to the Link component. The prefetch prop accepts a number which represents the number of milliseconds the page will be cached for. After the timeout expires, the page will be removed from the cache and the next time the user hover over the link, the page will be prefetched again.

import { Link } from "@lazarv/react-server/navigation";

export default function Home() {
  return (
    <div>
      <Link to="/about" prefetch={5000}>
        About
      </Link>
    </div>
  );
}

To programmatically prefetch a page you can use the prefetch function returned by the useClient hook.

import { useClient } from "@lazarv/react-server/client";

export default function Home() {
  const { prefetch } = useClient();

  return (
    <div>
      <button onMouseOver={() => prefetch("/about")}>About</button>
    </div>
  );
}

When the user navigates away from a page the router will cache the last page when you specify a rollback prop on the Link component. This will allow the user to navigate back to the previous page without having to wait for the server to render the page again. The provided value represents the number of milliseconds the page will be cached for. After the timeout expires, the page will be removed from the cache and the next time the user navigates back to the page, the page will be rendered again by the server.

import { Link } from "@lazarv/react-server/navigation";

export default function Home() {
  return (
    <div>
      <Link to="/about" rollback={5000}>
        About
      </Link>
    </div>
  );
}

To programmatically navigate to a new page you can use the navigate function returned by the useClient hook. It's recommended to use navigate in a React transition to render only the parts of the page that are changing.

import { startTransition } from "react";
import { useClient } from "@lazarv/react-server/client";

export default function Home() {
  const { navigate } = useClient();

  return (
    <div>
      <button onClick={() => startTransition(async () => navigate("/about"))}>
        About
      </button>
    </div>
  );
}

You can refresh the current page by using the <Refresh> client component exported by the @lazarv/react-server/navigation module or the refresh function returned by the useClient hook from the @lazarv/react-server/client module.

import { Refresh } from "@lazarv/react-server/navigation";

export default function Home() {
  return (
    <div>
      <Refresh>Click to refresh!</Refresh>
    </div>
  );
}

To programmatically refresh the current page you can use the refresh function returned by the useClient hook. Again, it's recommended to start a React transition for the page refresh.

import { startTransition } from "react";
import { useClient } from "@lazarv/react-server/client";

export default function Home() {
  const { refresh } = useClient();

  return (
    <div>
      <button onClick={() => startTransition(async () => refresh())}>
        Refresh
      </button>
    </div>
  );
}

You can use the ReactServerComponent to create an outlet which you can use for sub-page navigation. It's a modern React Server Component driven version of the <iframe> element. When using a Link or Refresh component or programmatically navigating with the navigate or replace functions, the client-side router will automatically update the content of the outlet by rendering the result of server-side rendering the outlet. You need to handle the server-side rendering of the outlet yourself using server-side routing and using the useOutlet helper function.

"use client";

import { Link, ReactServerComponent } from "@lazarv/react-server/navigation";

export default function Home() {
  return (
    <div>
      <Link to="/photos/1" target="modal">My photo</Link>
      <ReactServerComponent outlet="modal" />
    </div>
  );
}

There's four types of Link or Refresh navigation inside a ReactServerComponent. Unspecified, target, local and root. When using target on the Link or Refresh component, the navigation will only update the content of the outlet with the same name. When using local, the navigation will update the content of the parent outlet while URL of the current page is not updated this way. When using root, the navigation will update the content of the page. When using an unspecified behavior, the navigation will update the content of the page for each outlet if there are any outlets on the page.

"use client";

import { Link, ReactServerComponent } from "@lazarv/react-server/navigation";

export default function Home() {
  return (
    <div>
      <ReactServerComponent outlet="modal">
        <Link to="/photos/2" local>My photo</Link>
      </ReactServerComponent>
    </div>
  );
}

When using the ReactServerComponent with the defer prop, the content of the outlet will be rendered only when the user navigates to the page that contains the ReactServerComponent with the defer prop. This can be useful when you want to defer the rendering of the content of the outlet until the user navigates to the page that contains the ReactServerComponent with the defer prop. The content of the outlet will be fetched from the server.

You can also specify the url prop on the ReactServerComponent to specify the URL of the content of the outlet. This can be useful when you want to render the content of the outlet from a different URL than the current page.

Using both defer and url props on the ReactServerComponent you can achieve a similar behavior to the iframe element.

The useClient hook returns an object with the following properties:

You can use these functions for programmatic navigation.

import { startTransition } from "react";

import { useClient } from "@lazarv/react-server/client";

export default function Home() {
  const { navigate, replace, prefetch, refresh } = useClient();

  return (
    <div>
      <button onClick={() => startTransition(async () => navigate("/about"))}>
        About
      </button>
      <button onClick={() => startTransition(async () => replace("/about"))}>
        Replace
      </button>
      <button onMouseOver={() => prefetch("/about")}>Prefetch</button>
      <button onClick={() => startTransition(async () => refresh())}>
        Refresh
      </button>
    </div>
  );
}