Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 1x 1x 1x 1x 1x | import {
type ComponentType,
createElement,
isValidElement,
type ReactElement,
useMemo
} from 'react';
import {
RouterViewDepthContext,
useRoute,
useRouterViewDepth
} from './context';
import type { RouterViewProps } from './types';
import { resolveComponent } from './util';
/**
* RouterView component that renders the matched route component.
* Acts as a placeholder where route components are rendered based on the current route.
* Supports nested routing with automatic depth tracking.
*
* @param props - Component props
* @param props.fallback - Optional fallback component when no route matches
*
* @example
* ```tsx
* // Basic usage
* import { RouterView } from '@esmx/router-react';
*
* function App() {
* return (
* <div>
* <nav>
* <RouterLink to="/">Home</RouterLink>
* <RouterLink to="/about">About</RouterLink>
* </nav>
* <RouterView />
* </div>
* );
* }
* ```
*
* @example
* ```tsx
* // Nested routing
* // Routes: [
* // { path: '/users', component: UsersLayout, children: [
* // { path: ':id', component: UserProfile }
* // ]}
* // ]
*
* function UsersLayout() {
* return (
* <div>
* <h1>Users</h1>
* <RouterView /> // Renders UserProfile for /users/:id
* </div>
* );
* }
* ```
*
* @example
* ```tsx
* // With fallback
* import { RouterView } from '@esmx/router-react';
*
* function App() {
* return (
* <RouterView fallback={<div>Page not found</div>} />
* );
* }
* ```
*/
export function RouterView({ fallback }: RouterViewProps): ReactElement | null {
const route = useRoute();
const depth = useRouterViewDepth();
// Get the matched route at current depth
const matchedRoute = route.matched[depth];
// Resolve the component from the matched route
const Component = useMemo(() => {
if (!matchedRoute?.component) {
return null;
}
return resolveComponent(matchedRoute.component) as ComponentType<any>;
}, [matchedRoute?.component]);
// Render fallback if no component found
if (!Component) {
if (fallback) {
// If fallback is already a ReactElement, return it
if (isValidElement(fallback)) {
return fallback;
}
// If fallback is a component, render it
if (typeof fallback === 'function') {
return createElement(fallback as ComponentType);
}
// Return null for other cases (shouldn't happen with proper typing)
return null;
}
return null;
}
// Provide incremented depth for nested RouterViews using createElement
return createElement(
RouterViewDepthContext.Provider,
{ value: depth + 1 },
createElement(Component, { key: matchedRoute.compilePath })
);
}
RouterView.displayName = 'RouterView';
|