React Native integration for React Navigation providing navigation containers, deep linking, and platform-specific navigation behaviors.
—
React Navigation provides server-side rendering (SSR) support for web applications through the ServerContainer component and related utilities. This enables proper navigation state management during server rendering.
Container component specifically designed for server-side rendering contexts.
/**
* Container component for server rendering.
* Should only be used on the server with react-dom/server for SSR.
*/
function ServerContainer(
props: {
/** Location object to base the initial URL for SSR */
location: {
/** Current pathname */
pathname: string;
/** Query string */
search?: string;
/** Hash fragment */
hash?: string;
};
/** Child elements to render the content */
children: React.ReactNode;
} & React.RefAttributes<ServerContainerRef>
): React.ReactElement;
interface ServerContainerRef {
/** Get current navigation options during SSR */
getCurrentOptions(): Record<string, any> | undefined;
}Usage Examples:
import { ServerContainer } from '@react-navigation/native';
import { renderToString } from 'react-dom/server';
// Basic server-side rendering setup
function renderApp(req: Request) {
const location = {
pathname: req.url,
search: req.query ? `?${new URLSearchParams(req.query).toString()}` : '',
};
const html = renderToString(
<ServerContainer location={location}>
{/* Your navigation structure */}
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="About" component={AboutScreen} />
</Stack.Navigator>
</ServerContainer>
);
return html;
}
// Express.js server setup
app.get('*', (req, res) => {
const location = {
pathname: req.path,
search: req.url.includes('?') ? req.url.split('?')[1] : '',
};
const appHtml = renderToString(
<ServerContainer location={location}>
<App />
</ServerContainer>
);
const html = `
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<meta charset="utf-8" />
</head>
<body>
<div id="root">${appHtml}</div>
<script src="/client.js"></script>
</body>
</html>
`;
res.send(html);
});
// Next.js integration
function MyApp({ Component, pageProps, router }) {
if (typeof window === 'undefined') {
// Server-side rendering
return (
<ServerContainer location={{ pathname: router.asPath }}>
<Component {...pageProps} />
</ServerContainer>
);
}
// Client-side rendering
return (
<NavigationContainer>
<Component {...pageProps} />
</NavigationContainer>
);
}React context that provides server-side location information to child components.
interface ServerContextType {
/** Location object for server rendering */
location: {
pathname: string;
search?: string;
hash?: string;
};
}
// Server context is automatically provided by ServerContainer
// Access it using React.useContext if needed for custom components
const ServerContext: React.Context<ServerContextType | undefined>;Context Usage Examples:
import { ServerContext } from '@react-navigation/native';
// Access server location in components
function ServerAwareComponent() {
const serverContext = useContext(ServerContext);
if (serverContext) {
// Running on server
const { pathname, search } = serverContext.location;
console.log('Server rendering path:', pathname + (search || ''));
}
return <Text>Server-aware content</Text>;
}
// Conditional rendering based on server context
function ConditionalServerComponent() {
const serverContext = useContext(ServerContext);
const isServer = serverContext !== undefined;
return (
<View>
{isServer ? (
<Text>Rendered on server</Text>
) : (
<Text>Rendered on client</Text>
)}
</View>
);
}Handle navigation state during server-side rendering with proper hydration.
// Server navigation state management
interface SSRNavigationState {
/** Initial state derived from server location */
initialState?: NavigationState;
/** Whether hydration should preserve server state */
preserveState?: boolean;
}State Management Examples:
// Server-side state extraction
function getInitialNavigationState(pathname: string): NavigationState | undefined {
// Parse pathname to determine initial navigation state
if (pathname === '/') {
return {
routes: [{ name: 'Home', key: 'home' }],
index: 0,
};
} else if (pathname.startsWith('/profile/')) {
const userId = pathname.split('/')[2];
return {
routes: [
{ name: 'Home', key: 'home' },
{ name: 'Profile', key: 'profile', params: { userId } },
],
index: 1,
};
}
return undefined;
}
// SSR with navigation state
function serverRender(req: Request) {
const location = { pathname: req.path };
const initialState = getInitialNavigationState(req.path);
const html = renderToString(
<ServerContainer location={location}>
<NavigationContainer initialState={initialState}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
</NavigationContainer>
</ServerContainer>
);
return html;
}
// Client-side hydration
function clientHydrate() {
const initialState = window.__INITIAL_NAVIGATION_STATE__;
hydrateRoot(
document.getElementById('root'),
<NavigationContainer initialState={initialState}>
<App />
</NavigationContainer>
);
}Handle SEO metadata and document titles during server-side rendering.
// SEO support through server container ref
interface SSRMetadata {
title?: string;
description?: string;
canonicalUrl?: string;
openGraph?: Record<string, string>;
}SEO Examples:
// Extract metadata during SSR
function renderWithMetadata(req: Request) {
const serverContainerRef = useRef<ServerContainerRef>(null);
const location = { pathname: req.path };
const html = renderToString(
<ServerContainer ref={serverContainerRef} location={location}>
<App />
</ServerContainer>
);
// Extract navigation options for metadata
const options = serverContainerRef.current?.getCurrentOptions();
const title = options?.title || 'Default Title';
const description = options?.description || 'Default description';
const fullHtml = `
<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
<meta name="description" content="${description}" />
<meta property="og:title" content="${title}" />
<meta property="og:description" content="${description}" />
<link rel="canonical" href="${req.protocol}://${req.get('host')}${req.path}" />
</head>
<body>
<div id="root">${html}</div>
</body>
</html>
`;
return fullHtml;
}
// Screen with SEO metadata
function ProfileScreen({ route }) {
const { userId } = route.params;
useLayoutEffect(() => {
navigation.setOptions({
title: `Profile - ${userId}`,
description: `View profile information for user ${userId}`,
});
}, [userId]);
return <ProfileContent userId={userId} />;
}Handle errors gracefully during server-side rendering.
// SSR error handling patterns
interface SSRErrorBoundary {
/** Fallback component for server errors */
fallback: React.ComponentType<{ error: Error }>;
/** Error logging during SSR */
onError?: (error: Error) => void;
}Error Handling Examples:
// Server error boundary
class SSRErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// Log error during SSR
console.error('SSR Navigation Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h1>Navigation Error</h1>
<p>Unable to render navigation on server</p>
</div>
);
}
return this.props.children;
}
}
// Safe SSR rendering
function safeServerRender(req: Request) {
try {
const location = { pathname: req.path };
const html = renderToString(
<SSRErrorBoundary>
<ServerContainer location={location}>
<App />
</ServerContainer>
</SSRErrorBoundary>
);
return html;
} catch (error) {
console.error('Server rendering failed:', error);
// Return minimal HTML fallback
return `
<div id="root">
<div>Loading...</div>
<script>
// Client will take over
window.__SSR_ERROR__ = true;
</script>
</div>
`;
}
}
// Client-side fallback handling
function clientWithFallback() {
const hasSSRError = window.__SSR_ERROR__;
if (hasSSRError) {
// Full client-side rendering
render(
<NavigationContainer>
<App />
</NavigationContainer>,
document.getElementById('root')
);
} else {
// Normal hydration
hydrateRoot(
document.getElementById('root'),
<NavigationContainer>
<App />
</NavigationContainer>
);
}
}Properly detect and handle server-side rendering context.
// Platform detection utilities
interface PlatformDetection {
isServer: boolean;
isClient: boolean;
canUseDOM: boolean;
}Platform Detection Examples:
// Universal platform detection
const isServer = typeof window === 'undefined';
const isClient = typeof window !== 'undefined';
// Navigation container selection
function UniversalNavigationContainer({ children, ...props }) {
if (isServer) {
return (
<ServerContainer {...props}>
{children}
</ServerContainer>
);
}
return (
<NavigationContainer {...props}>
{children}
</NavigationContainer>
);
}
// Feature detection during SSR
function FeatureAwareComponent() {
const [canUseFeature, setCanUseFeature] = useState(false);
useEffect(() => {
// Only run on client
if (typeof window !== 'undefined') {
setCanUseFeature(true);
}
}, []);
return (
<View>
{canUseFeature ? (
<ClientOnlyFeature />
) : (
<ServerSafeContent />
)}
</View>
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-navigation--native