routerEdit this page

Server-side routing

The built-in low-level routing solution in @lazarv/react-server is sufficient for simple use cases, but it is not recommended for more complex applications. For a more advanced routing solution, use the file-system based router or a third-party router like React Router or TanStack Router.

You can wrap your components into a Route component imported from @lazarv/react-server/router to define a route. You have to define the absolute path pattern for the route where the child components of the Route component will need to render. You can also define the route component as the element prop of the Route component.

import { Route } from '@lazarv/react-server/router';

export default function App() {
  return (
    <Route path="/about">
      <About />
    </Route>
    <Route path="/readme" element={<Readme />} />
  );
}

When you define a route, it will match any path that starts with the defined path. If you want to match only the exact path, you can use the exact prop.

import { Route } from '@lazarv/react-server/router';

export default function App() {
  return (
    <Route path="/about" exact>
      <About />
    </Route>
  );
}

You can nest routes by defining a route inside another route.

import { Route } from '@lazarv/react-server/router';

function About() {
  return (
    <div>
      <h1>About</h1>
      <Route path="/about/team" element={<Tean />} />
    </div>
  );
}

export default function App() {
  return (
    <Route path="/about" element={<About />} />
  );
}

To define how to render the children of a route, you can use the render prop. The render prop accepts a function that receives the children prop together with all route params as props and returns a React element.

import { Route } from '@lazarv/react-server/router';

function Layout({ children }) {
  return (
    <div>
      <h1>Layout</h1>
      {children}
    </div>
  );
}

export default function App() {
  return (
    <Route path="/" render={Layout}>
      <Route path="/" exact element={<Home />} />
      <Route path="/about" element={<About />} />
    </Route>
  );
}

You can define route parameters by wrapping a path segment in brackets. The value of the route parameter will be available as a prop when you use render on the Route component.

import { Route } from '@lazarv/react-server/router';

function User({ id }) {
  return (
    <div>
      <h1>User ID</h1>
      <h2>{id}</h2>
    </div>
  );
}

export default function App() {
  return (
    <Route path="/users/[id]" render={User} />
  );
}

You can define variable length route parameters by wrapping a path segment in brackets and prefixing it with three dots. The value of the route parameter will be available in the params prop of the Route component.

import { Route } from '@lazarv/react-server/router';

export default function App() {
  return (
    <Route path="/files/[...path]" render={File} />
  );
}

You can define a custom matcher for a route parameter by wrapping a path segment in brackets and specifying the matcher name after the parameter name. The path pattern will only match if the route parameter matches the specified matcher.

import { Route } from '@lazarv/react-server/router';

const matchers = {
  number: (value) => /^\d+$/.test(value),
};

export default function App() {
  return (
    <Route path="/files/[id=number]" render={File} matchers={matchers} />
  );
}

You can define a fallback route by defining a route with a path of * or using the fallback prop on the Route component. The fallback route will match any path that does not match any other route.

import { Route } from '@lazarv/react-server/router';

export default function App() {
  return (
    <Route path="/about" element={<About />} />
    <Route fallback element={<NotFound />} />
  );
}

If you want a route to render only it's children when using client-side navigation, you can set the value of the standalone prop on the Route component to be false. This will prevent the route from using it's render function when the path matches the route. Upon client-side navigation or refreshing, the route will only render it's children.

import { Route } from '@lazarv/react-server/router';

function Layout({ children }) {
  return (
    <div>
      <h1>Layout</h1>
      {children}
    </div>
  );
}

export default function App() {
  return (
    <Route path="/" render={Layout} standalone={false}>
      <Route path="/" exact element={<Home />} />
      <Route path="/about" element={<About />} />
    </Route>
  );
}

You can redirect to any other location by using the redirect function in a component. More precisely, you can use redirect anywhere during server-side rendering, but it will throw a RedirectError. The framework will catch this error and send a redirect response to the client.

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

export default function App() {
  return redirect("/user");
}

You can use the rewrite function to change the pathname in the URL of the current request. This is useful when you want to change the URL of the current request without redirecting the client. Best used in a middleware.

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

export default function App() {
  return rewrite("/user");
}

Middlewares are functions that are executed before the route handler. They can be used for many things, like authentication, logging, parsing, etc.

Export an async function named init$ from your entry module. This function can initialize your request handler that will be the middleware runner. The init$ function needs to return with an async function. This function will be the middleware runner.

// index.jsx

export async function init$() {
  return async (context) {
    // do something
  };
}

You can use all functions available from the @lazarv/react-server module in your middleware. You can redirect or rewrite the request, manage cookies or add headers to the response. Everything is available and possible that would be available in a React server component.