Documentation

App shell

Create a RouterShell with app context, DevTools instrumentation, pending UI, and cleanup.

A production app usually creates the router inside a small shell component. The shell can read app-level dependencies, pass them as router context, register instrumentation, and dispose the router when the shell unmounts.

import { useEffect, useMemo, type JSX } from 'react';
import { useRelayEnvironment } from 'react-relay';
import {
  createDevtoolsBridgeInstrumentation,
  createRouter,
  RouterRenderer,
  RoutingContext,
} from '@plumile/router';

import { getRoutes } from './routes/index.js';
import { RouteFallback } from './RouteFallback.js';
import { RoutePendingBar } from './RoutePendingBar.js';

export function RouterShell(): JSX.Element {
  const relayEnvironment = useRelayEnvironment();

  const routes = useMemo(() => getRoutes(), []);
  const devtools = useMemo(() => createDevtoolsBridgeInstrumentation(), []);
  const context = useMemo(() => ({ relayEnvironment }), [relayEnvironment]);

  const router = useMemo(
    () =>
      createRouter(routes, {
        context,
        instrumentations: [devtools],
      }),
    [context, devtools, routes],
  );

  useEffect(() => {
    return () => router.cleanup();
  }, [router]);

  return (
    <RoutingContext.Provider value={router.context}>
      <RouterRenderer
        enableTransition
        fallback={<RouteFallback />}
        pending={<RoutePendingBar />}
      />
    </RoutingContext.Provider>
  );
}

Use context for dependencies every route prepare function needs, such as a Relay environment. Use pending for transition feedback and fallback for the Suspense fallback while route resources resolve.