#
AppRouter
A component that sets up Squide's primitives with a React Router instance.
The AppRouter
component is required for any Squide application.
#
Reference
<AppRouter waitForMsw={boolean} waitForPublicData={boolean} waitForProtectedData={boolean}>
{({ rootRoute, registeredRoutes, routerProviderProps }) => ( ... )}
</AppRouter>
#
Properties
waitForMsw
: Aboolean
value indicating whether or not Squide should delay the rendering of the requested page until the Mock Service Worker request handlers are registered.waitForPublicData
: An optionalboolean
value indicating whether or not Squide should delay the rendering of the requested page until the public data is ready. The default value isfalse
.waitForProtectedData
: An optionalboolean
value indicating whether or not Squide should delay the rendering of the requested page until the protected data is ready. The default value isfalse
.children
: A render function defining a RouterProvider component withrootRoute
,registeredRoutes
androuterProviderProps
.
#
Usage
#
Define a router provider
The rootRoute
component provided as an argument to the AppRouter
rendering function must always be rendered as a parent of the registeredRoutes
.
import { AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
export function App() {
<AppRouter waitForMsw={false}>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
children: registeredRoutes
}
])}
{...routerProviderProps}
/>
);
}}
</AppRouter>
}
#
Define a loading component
A BootstrappingRoute
component is introduced in the following example because the useIsBootstrapping hook must be rendered as a child of rootRoute
.
import { useIsBootstrapping, AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter, Outlet } from "react-router-dom";
function BootstrappingRoute() {
if (useIsBootstrapping()) {
return <div>Loading...</div>;
}
return <Outlet />;
}
export function App() {
return (
<AppRouter waitForMsw={false}>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
children: [
{
element: <BootstrappingRoute />,
children: registeredRoutes
}
]
}
])}
{...routerProviderProps}
/>
);
}}
</AppRouter>
);
}
#
Define a root error boundary
A React Router errorElement retrieves the current error using the useRouteError hook.
The root error boundary should always wrap the registeredRoutes
and, when application, the BootstrapingRoute
component.
import { useRouteError } from "react-router-dom";
export function RootErrorBoundary() {
const error = useRouteError();
return (
<div>
<h2>Unmanaged error</h2>
<p>An unmanaged error occurred and the application is broken, try refreshing your browser.</p>
</div>
);
}
import { AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { RootErrorBoundary } from "./RootErrorBoundary.tsx";
export function App() {
return (
<AppRouter waitForMsw={false}>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
errorElement: <RootErrorBoundary />,
children: registeredRoutes
}
])}
{...routerProviderProps}
/>
);
}}
</AppRouter>
);
}
#
Delay rendering until MSW is ready
import { AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
export function App() {
return (
<AppRouter waitForMsw>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
children: registeredRoutes
}
])}
{...routerProviderProps}
/>
);
}}
</AppRouter>
);
}
#
Delay rendering until the public data is ready
A BootstrappingRoute
component is introduced in the following example because the usePublicDataQueries hook must be rendered as a child of rootRoute
.
import { useIsBootstrapping, usePublicDataQueries, AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter, Outlet } from "react-router-dom";
import { FeatureFlagsContext } from "@sample/shared";
import { getFeatureFlagsQuery } from "./getFeatureFlagsQuery.ts";
function BootstrappingRoute() {
const [featureFlags] = usePublicDataQueries([getFeatureFlagsQuery]);
if (useIsBootstrapping()) {
return <div>Loading...</div>;
}
return (
<FeatureFlagsContext.Provider value={featureFlags}>
<Outlet />
</FeatureFlagsContext.Provider>
);
}
export function App() {
return (
<AppRouter
waitForMsw
waitForPublicData
>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
children: [
{
element: <BootstrappingRoute />,
children: registeredRoutes
}
]
}
])}
{...routerProviderProps}
/>
);
}}
</AppRouter>
);
}
#
Delay rendering until the protected data is ready
A BootstrappingRoute
component is introduced in the following example because the useProtectedDataQueries hook must be rendered as a child of rootRoute
.
import { useIsBootstrapping, useProtectedDataQueries, AppRouter } from "@squide/firefly";
import { RouterProvider, createBrowserRouter, Outlet } from "react-router-dom";
import { SessionContext, isApiError } from "@sample/shared";
import { getSessionQuery } from "./getSessionQuery.ts";
function BootstrappingRoute() {
const [session] = useProtectedDataQueries(
[getSessionQuery],
error => isApiError(error) && error.status === 401
);
if (useIsBootstrapping()) {
return <div>Loading...</div>;
}
return (
<SessionContext.Provider value={session}>
<Outlet />
</SessionContext.Provider>
);
}
export function App() {
return (
<AppRouter
waitForMsw
waitForProtectedData
>
{({ rootRoute, registeredRoutes, routerProviderProps }) => {
return (
<RouterProvider
router={createBrowserRouter([
{
element: rootRoute,
children: [
{
element: <BootstrappingRoute />,
children: registeredRoutes
}
]
}
])}
{...routerProviderProps}
/>
);
}}
</AppRouter>
);
}