CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-navigation--native

React Native integration for React Navigation providing navigation containers, deep linking, and platform-specific navigation behaviors.

Pending
Overview
Eval results
Files

server-side-rendering.mddocs/

Server-Side Rendering

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.

Capabilities

ServerContainer Component

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>
  );
}

Server Context

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>
  );
}

SSR Navigation State

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>
  );
}

SEO and Meta Tags

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} />;
}

Error Handling

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>
    );
  }
}

Platform Detection

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

docs

deep-linking.md

index.md

link-components.md

navigation-container.md

navigation-hooks.md

server-side-rendering.md

static-navigation.md

theming.md

tile.json