logo-text
React Native WebCross-PlatformWeb Development

React Native Web Complete Guide: Build Cross-Platform Apps for Web 2025

By Viewlytics Team17 min readJune 2, 2025

React Native Web enables you to run React Native components and APIs on the web, creating truly universal applications. This comprehensive guide covers everything from setup to deployment, helping you build performant cross-platform apps that work seamlessly across mobile and web.

1. Understanding React Native Web

What is React Native Web?

React Native Web is an accessible implementation of React Native's Components and APIs that is interoperable with React DOM. It allows you to run React Native code on the web without modification, enabling true code sharing across iOS, Android, and web platforms.

Key Benefits:
  • 🌐 Single codebase for mobile and web
  • ♿ Built-in accessibility features
  • 📱 Responsive design support
  • 🎨 Consistent styling across platforms
  • 🔧 Incremental adoption possible

Major companies like Facebook, Twitter, and Flipkart use React Native Web in production, proving its reliability and scalability.

React Native Web vs Traditional Web Development

Here's how React Native Web compares to traditional web development approaches:

AspectReact Native WebTraditional React
Code Sharing95%+ across platformsWeb-only, separate mobile apps
Component LibraryUnified React Native componentsSeparate web component libraries
StylingStyleSheet API (CSS-in-JS)CSS, styled-components, etc.
Bundle Size~42KB gzipped baseVaries by setup
Learning CurveReact Native knowledge requiredWeb-specific knowledge

2. Setting Up React Native Web

New Project Setup

The easiest way to start with React Native Web is using Expo, which has built-in web support:

# Create new Expo project with web support
npx create-expo-app MyUniversalApp --template

# Navigate to project
cd MyUniversalApp

# Install web dependencies
npx expo install react-dom react-native-web @expo/webpack-config

# Start development server
npx expo start --web

For vanilla React Native projects, you can add web support manually:

# Install React Native Web
npm install react-native-web

# Install dev dependencies
npm install --save-dev @babel/preset-env @babel/preset-react
npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save-dev babel-loader html-webpack-plugin

Webpack Configuration

Configure Webpack to properly resolve React Native Web modules:

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './index.web.js',
  mode: 'development',
  module: {
    rules: [
      {
        test: /.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react',
              'module:metro-react-native-babel-preset'
            ]
          }
        }
      }
    ]
  },
  resolve: {
    alias: {
      'react-native$': 'react-native-web',
      'react-native-svg': 'react-native-svg-web'
    },
    extensions: ['.web.js', '.js', '.jsx', '.ts', '.tsx']
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ],
  devServer: {
    historyApiFallback: true,
    port: 3000
  }
};

Entry Point Setup

Create a web-specific entry point for your application:

// index.web.js
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import App from './App';

// Register the app for web
AppRegistry.registerComponent(appName, () => App);
AppRegistry.runApplication(appName, {
  initialProps: {},
  rootTag: document.getElementById('app-root')
});
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React Native Web App</title>
  <style>
    body {
      margin: 0;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    }
    #app-root {
      display: flex;
      flex: 1;
      height: 100vh;
    }
  </style>
</head>
<body>
  <div id="app-root"></div>
</body>
</html>

3. Core Components and APIs

Universal Components

React Native Web provides web implementations for all core React Native components:

import React from 'react';
import { 
  View, 
  Text, 
  StyleSheet, 
  ScrollView, 
  TouchableOpacity,
  TextInput,
  Image
} from 'react-native';

function UniversalComponent() {
  return (
    <View style={styles.container}>
      <ScrollView style={styles.scrollView}>
        <Text style={styles.title}>Universal App</Text>
        
        <Image 
          source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
          style={styles.image}
          accessibilityLabel="React Native Logo"
        />
        
        <TextInput
          style={styles.input}
          placeholder="Enter text here"
          accessibilityLabel="Text input field"
        />
        
        <TouchableOpacity 
          style={styles.button}
          onPress={() => alert('Button pressed!')}
          accessibilityRole="button"
        >
          <Text style={styles.buttonText}>Press Me</Text>
        </TouchableOpacity>
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  scrollView: {
    flex: 1,
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
    marginBottom: 20,
    color: '#333',
  },
  image: {
    width: 100,
    height: 100,
    alignSelf: 'center',
    marginBottom: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 8,
    padding: 12,
    marginBottom: 20,
    backgroundColor: 'white',
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
  },
});

export default UniversalComponent;

Platform-Specific Code

Use platform extensions or Platform API to write platform-specific code:

import { Platform } from 'react-native';

// Method 1: Platform API
const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: Platform.select({
      ios: 20,
      android: 25,
      web: 0,
      default: 0
    }),
  },
  text: {
    ...Platform.select({
      web: {
        cursor: 'pointer',
        userSelect: 'none',
      },
      default: {},
    }),
  }
});

// Method 2: Platform-specific files
// Component.ios.js
// Component.android.js  
// Component.web.js
// Component.js (fallback)

// Method 3: Conditional rendering
function CrossPlatformComponent() {
  return (
    <View>
      {Platform.OS === 'web' ? (
        <div style={{ cursor: 'pointer' }}>Web-specific content</div>
      ) : (
        <Text>Mobile content</Text>
      )}
    </View>
  );
}

Web-Specific Features

Leverage web-specific APIs and features when needed:

import React, { useEffect } from 'react';
import { Platform } from 'react-native';

function WebSpecificFeatures() {
  useEffect(() => {
    if (Platform.OS === 'web') {
      // Set document title
      document.title = 'My Universal App';
      
      // Add meta tags
      const metaDescription = document.createElement('meta');
      metaDescription.name = 'description';
      metaDescription.content = 'A universal React Native app';
      document.head.appendChild(metaDescription);
      
      // Handle keyboard events
      const handleKeyPress = (event) => {
        if (event.key === 'Escape') {
          // Handle escape key
        }
      };
      
      window.addEventListener('keydown', handleKeyPress);
      return () => window.removeEventListener('keydown', handleKeyPress);
    }
  }, []);

  return null;
}

4. Styling Best Practices

Responsive Design

Create responsive layouts using Flexbox and dimension-based styling:

import React from 'react';
import { View, Text, StyleSheet, useWindowDimensions } from 'react-native';

function ResponsiveLayout() {
  const { width, height } = useWindowDimensions();
  
  const isDesktop = width >= 1024;
  const isTablet = width >= 768 && width < 1024;
  const isMobile = width < 768;

  return (
    <View style={styles.container}>
      <View style={[
        styles.content,
        isDesktop && styles.desktopContent,
        isTablet && styles.tabletContent,
        isMobile && styles.mobileContent
      ]}>
        <Text style={styles.title}>
          Responsive Layout ({width}x{height})
        </Text>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  content: {
    flex: 1,
    padding: 20,
    alignSelf: 'center',
  },
  desktopContent: {
    maxWidth: 1200,
    flexDirection: 'row',
    flexWrap: 'wrap',
  },
  tabletContent: {
    maxWidth: 768,
    paddingHorizontal: 40,
  },
  mobileContent: {
    width: '100%',
    paddingHorizontal: 16,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

CSS-in-JS Best Practices

Follow React Native Web styling conventions for optimal performance:

import { StyleSheet } from 'react-native';

// ✅ Good: Use StyleSheet.create for performance
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#ffffff',
  },
  // Use object shorthand for better readability
  centerContent: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  // Group related styles
  text: {
    fontSize: 16,
    lineHeight: 24,
    color: '#333333',
  },
  boldText: {
    fontWeight: 'bold',
  },
});

// ✅ Good: Combine styles efficiently
<Text style={[styles.text, styles.boldText]}>
  Bold Text
</Text>

// ❌ Avoid: Inline styles for static values
<View style={{ flex: 1, backgroundColor: '#ffffff' }}>

// ✅ Better: Use StyleSheet for static styles
<View style={styles.container}>

// ✅ Good: Use inline styles for dynamic values only
<View style={[styles.container, { opacity: isVisible ? 1 : 0 }]}>

// Web-specific styles using Platform
const webStyles = Platform.OS === 'web' ? {
  cursor: 'pointer',
  transition: 'all 0.2s ease',
  ':hover': {
    backgroundColor: '#f0f0f0',
  }
} : {};

Typography and Fonts

Handle fonts consistently across platforms:

// Custom font setup
const typography = StyleSheet.create({
  heading1: {
    fontSize: 32,
    fontWeight: 'bold',
    lineHeight: 40,
    fontFamily: Platform.select({
      ios: 'San Francisco',
      android: 'Roboto',
      web: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
    }),
  },
  body: {
    fontSize: 16,
    lineHeight: 24,
    fontFamily: Platform.select({
      ios: 'San Francisco',
      android: 'Roboto', 
      web: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
    }),
  },
  monospace: {
    fontFamily: Platform.select({
      ios: 'SF Mono',
      android: 'monospace',
      web: 'Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
    }),
  },
});

// Usage
function TypographyExample() {
  return (
    <View>
      <Text style={typography.heading1}>Main Heading</Text>
      <Text style={typography.body}>Body text content</Text>
      <Text style={typography.monospace}>console.log('Code example');</Text>
    </View>
  );
}

5. Performance Optimization

Bundle Size Optimization

Optimize your React Native Web bundle for better loading performance:

// webpack.config.js - Production optimizations
const path = require('path');

module.exports = {
  // ... other config
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\/]node_modules[\/]/,
          name: 'vendors',
          chunks: 'all',
        },
        react: {
          test: /[\/]node_modules[\/](react|react-dom)[\/]/,
          name: 'react',
          chunks: 'all',
        }
      }
    }
  },
  resolve: {
    alias: {
      'react-native$': 'react-native-web',
      // Tree shake unused modules
      'react-native-vector-icons$': 'react-native-vector-icons/dist/FontAwesome',
    },
    // Prioritize web extensions
    extensions: ['.web.js', '.web.ts', '.web.tsx', '.js', '.ts', '.tsx']
  }
};

// Use dynamic imports for code splitting
const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

Component Performance

Optimize components for smooth web performance:

import React, { memo, useMemo, useCallback } from 'react';
import { FlatList, View, Text } from 'react-native';

// Memoize expensive list items
const ListItem = memo(function ListItem({ item, onPress }) {
  const handlePress = useCallback(() => {
    onPress(item.id);
  }, [item.id, onPress]);

  return (
    <TouchableOpacity onPress={handlePress}>
      <Text>{item.title}</Text>
    </TouchableOpacity>
  );
});

// Optimize FlatList for web
function OptimizedList({ data }) {
  const renderItem = useCallback(({ item }) => (
    <ListItem item={item} onPress={handleItemPress} />
  ), []);

  const keyExtractor = useCallback((item) => item.id, []);

  const getItemLayout = useCallback((data, index) => ({
    length: 60,
    offset: 60 * index,
    index,
  }), []);

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      windowSize={10}
      initialNumToRender={20}
    />
  );
}

Image Optimization

Handle images efficiently across platforms:

import React from 'react';
import { Image, Platform } from 'react-native';

function OptimizedImage({ src, width, height, ...props }) {
  // Use different image sources for web
  const imageSource = Platform.OS === 'web' 
    ? {
        uri: src,
        // Use responsive images on web
        ...(width && height && {
          width,
          height,
        })
      }
    : { uri: src };

  return (
    <Image
      source={imageSource}
      style={[
        { width, height },
        Platform.OS === 'web' && {
          objectFit: 'cover',
          maxWidth: '100%',
          height: 'auto',
        }
      ]}
      // Web-specific props
      {...(Platform.OS === 'web' && {
        loading: 'lazy',
        decoding: 'async',
      })}
      {...props}
    />
  );
}

// Usage with responsive images
function ResponsiveImage() {
  return (
    <OptimizedImage
      src="https://example.com/image.jpg"
      width={300}
      height={200}
      alt="Description for accessibility"
    />
  );
}

6. Navigation and Routing

React Navigation Web Support

React Navigation works seamlessly with React Native Web:

# Install React Navigation for web
npm install @react-navigation/native @react-navigation/web
npm install react-native-screens react-native-safe-area-context
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Platform } from 'react-native';

const Stack = createStackNavigator();

function App() {
  return (
    <NavigationContainer
      // Web-specific linking configuration
      linking={{
        prefixes: ['https://myapp.com', 'myapp://'],
        config: {
          screens: {
            Home: '/',
            Profile: '/profile/:userId',
            Settings: '/settings',
          },
        },
      }}
      // Fallback for web
      fallback={<div>Loading...</div>}
    >
      <Stack.Navigator
        screenOptions={{
          // Web-specific header styling
          ...(Platform.OS === 'web' && {
            headerStyle: {
              backgroundColor: '#f8f9fa',
            }
          })
        }}
      >
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
        <Stack.Screen name="Settings" component={SettingsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Deep Linking and URLs

Handle URLs and deep linking properly on web:

import { useLinking } from '@react-navigation/native';
import { Platform } from 'react-native';

function useWebLinking() {
  const { getStateFromPath, getPathFromState } = useLinking();

  // Custom URL handling for web
  React.useEffect(() => {
    if (Platform.OS === 'web') {
      // Handle browser back/forward buttons
      const handlePopState = (event) => {
        // Handle state changes
      };

      window.addEventListener('popstate', handlePopState);
      return () => window.removeEventListener('popstate', handlePopState);
    }
  }, []);

  return {
    getStateFromPath,
    getPathFromState,
  };
}

// SEO-friendly navigation
function SEOFriendlyScreen({ route }) {
  React.useEffect(() => {
    if (Platform.OS === 'web') {
      // Update document title
      document.title = `${route.name} - My App`;
      
      // Update meta description
      const metaDescription = document.querySelector('meta[name="description"]');
      if (metaDescription) {
        metaDescription.content = `Content for ${route.name}`;
      }
    }
  }, [route.name]);

  return (
    // Component content
  );
}

7. Testing Strategies

Unit Testing

Test your universal components across platforms:

# Install testing dependencies
npm install --save-dev @testing-library/react-native
npm install --save-dev @testing-library/jest-dom
npm install --save-dev jest-environment-jsdom
// __tests__/UniversalComponent.test.js
import React from 'react';
import { render, fireEvent } from '@testing-library/react-native';
import UniversalComponent from '../UniversalComponent';

// Mock Platform for testing
jest.mock('react-native/Libraries/Utilities/Platform', () => ({
  OS: 'web',
  select: (platforms) => platforms.web || platforms.default,
}));

describe('UniversalComponent', () => {
  it('renders correctly on web', () => {
    const { getByText, getByRole } = render(<UniversalComponent />);
    
    expect(getByText('Universal App')).toBeTruthy();
    expect(getByRole('button', { name: 'Press Me' })).toBeTruthy();
  });

  it('handles button press', () => {
    const mockAlert = jest.spyOn(window, 'alert').mockImplementation();
    const { getByRole } = render(<UniversalComponent />);
    
    fireEvent.press(getByRole('button', { name: 'Press Me' }));
    expect(mockAlert).toHaveBeenCalledWith('Button pressed!');
    
    mockAlert.mockRestore();
  });

  it('applies correct styles for web platform', () => {
    const { getByTestId } = render(<UniversalComponent />);
    const button = getByTestId('press-button');
    
    expect(button).toHaveStyle({
      cursor: 'pointer',
    });
  });
});

End-to-End Testing

Use Playwright or Cypress for web-specific E2E testing:

// e2e/web.spec.js (Playwright)
import { test, expect } from '@playwright/test';

test.describe('React Native Web App', () => {
  test('should navigate and interact correctly', async ({ page }) => {
    await page.goto('http://localhost:3000');
    
    // Test responsive design
    await page.setViewportSize({ width: 1200, height: 800 });
    await expect(page.locator('[data-testid="desktop-layout"]')).toBeVisible();
    
    await page.setViewportSize({ width: 375, height: 667 });
    await expect(page.locator('[data-testid="mobile-layout"]')).toBeVisible();
    
    // Test navigation
    await page.click('text=Profile');
    await expect(page).toHaveURL(/.*profile/);
    
    // Test form interactions
    await page.fill('[placeholder="Enter text here"]', 'Test input');
    await page.click('text=Submit');
    
    // Test accessibility
    await expect(page.locator('button')).toHaveAttribute('aria-label');
  });

  test('should work with keyboard navigation', async ({ page }) => {
    await page.goto('http://localhost:3000');
    
    // Test keyboard navigation
    await page.keyboard.press('Tab');
    await page.keyboard.press('Enter');
    
    // Test keyboard shortcuts
    await page.keyboard.press('Escape');
  });
});

8. Deployment and Production

Build Configuration

Configure your build process for production deployment:

// webpack.prod.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

module.exports = {
  mode: 'production',
  entry: './index.web.js',
  output: {
    path: path.resolve(__dirname, 'web-build'),
    filename: 'static/js/[name].[contenthash:8].js',
    chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
    publicPath: '/',
  },
  optimization: {
    minimize: true,
    splitChunks: {
      chunks: 'all',
      name: false,
    },
    runtimeChunk: {
      name: entrypoint => `runtime-${entrypoint.name}`,
    },
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true,
      },
    }),
    // Analyze bundle size
    process.env.ANALYZE && new BundleAnalyzerPlugin(),
  ].filter(Boolean),
};

Static Site Generation

Generate static sites for better SEO and performance:

// scripts/static-export.js
const { renderToStaticMarkup } = require('react-dom/server');
const { AppRegistry } = require('react-native-web');
const fs = require('fs');
const path = require('path');

// Import your root component
const App = require('../App').default;

// Register component
AppRegistry.registerComponent('App', () => App);

// Get the component
const { element, getStyleElement } = AppRegistry.getApplication('App');

// Render to static HTML
const html = renderToStaticMarkup(element);
const css = renderToStaticMarkup(getStyleElement());

// Generate HTML template
const template = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React Native Web App</title>
  ${css}
</head>
<body>
  <div id="root">${html}</div>
  <script src="/bundle.js"></script>
</body>
</html>
`;

// Write to file
fs.writeFileSync(path.join(__dirname, '../web-build/index.html'), template);
console.log('Static HTML generated successfully!');

Progressive Web App (PWA)

Convert your React Native Web app into a PWA:

// public/manifest.json
{
  "name": "My Universal App",
  "short_name": "UniversalApp",
  "description": "A universal React Native app",
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#007AFF",
  "background_color": "#ffffff",
  "icons": [
    {
      "src": "icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icon-512x512.png", 
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}
// public/sw.js - Service Worker
const CACHE_NAME = 'universal-app-v1';
const urlsToCache = [
  '/',
  '/static/js/bundle.js',
  '/static/css/main.css',
  '/icon-192x192.png'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => cache.addAll(urlsToCache))
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then((response) => {
        // Return cached version or fetch from network
        return response || fetch(event.request);
      })
  );
});

// Register service worker in your app
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then((registration) => {
        console.log('SW registered: ', registration);
      })
      .catch((registrationError) => {
        console.log('SW registration failed: ', registrationError);
      });
  });
}

9. Common Challenges and Solutions

Library Compatibility

Handle React Native libraries that don't support web:

// utils/platformModules.js
import { Platform } from 'react-native';

// Conditional imports based on platform
export const getLocationModule = () => {
  if (Platform.OS === 'web') {
    // Use browser geolocation API
    return {
      getCurrentPosition: (success, error, options) => {
        navigator.geolocation.getCurrentPosition(success, error, options);
      }
    };
  } else {
    // Use react-native-geolocation-service for mobile
    return require('react-native-geolocation-service').default;
  }
};

// Mock native modules for web
export const mockNativeModule = (moduleName) => {
  if (Platform.OS === 'web') {
    console.warn(`${moduleName} is not available on web`);
    return {
      // Provide web alternatives or no-ops
    };
  }
  return require(moduleName);
};

// Platform-specific component imports
export const SafeAreaView = Platform.OS === 'web' 
  ? require('react-native').View 
  : require('react-native-safe-area-context').SafeAreaView;

Performance Issues

Address common performance bottlenecks:

import React, { useMemo, useCallback } from 'react';
import { Platform, FlatList } from 'react-native';

// Optimize large lists for web
function OptimizedFlatList({ data, ...props }) {
  const webOptimizations = useMemo(() => {
    if (Platform.OS === 'web') {
      return {
        // Use virtual scrolling for large datasets
        removeClippedSubviews: true,
        maxToRenderPerBatch: 50,
        windowSize: 10,
        // Reduce re-renders
        getItemLayout: props.getItemLayout || ((data, index) => ({
          length: 50, // Estimated item height
          offset: 50 * index,
          index,
        })),
      };
    }
    return {};
  }, [props.getItemLayout]);

  return (
    <FlatList
      {...props}
      {...webOptimizations}
      data={data}
    />
  );
}

// Debounce search for better performance
function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = React.useState(value);

  React.useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

function SearchComponent() {
  const [searchTerm, setSearchTerm] = React.useState('');
  const debouncedSearchTerm = useDebounce(searchTerm, 300);

  const handleSearch = useCallback((text) => {
    setSearchTerm(text);
  }, []);

  React.useEffect(() => {
    if (debouncedSearchTerm) {
      // Perform search
    }
  }, [debouncedSearchTerm]);

  return (
    <TextInput
      value={searchTerm}
      onChangeText={handleSearch}
      placeholder="Search..."
    />
  );
}

10. Advanced Topics

Server-Side Rendering (SSR)

Implement SSR for better SEO and initial load performance:

// server/ssr.js
const React = require('react');
const { renderToString } = require('react-dom/server');
const { AppRegistry } = require('react-native-web');
const express = require('express');

const App = require('../App').default;

// Register the app
AppRegistry.registerComponent('App', () => App);

const app = express();

app.get('*', (req, res) => {
  const { element, getStyleElement } = AppRegistry.getApplication('App', {
    initialProps: {},
    rootTag: 'app-root'
  });

  // Render app to string
  const appHtml = renderToString(element);
  const appStyles = renderToString(getStyleElement());

  const html = `
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>React Native Web SSR</title>
      ${appStyles}
    </head>
    <body>
      <div id="app-root">${appHtml}</div>
      <script src="/bundle.js"></script>
    </body>
    </html>
  `;

  res.send(html);
});

app.listen(3000, () => {
  console.log('SSR server running on port 3000');
});

Micro-Frontend Architecture

Scale large applications using micro-frontend patterns:

// Module federation for React Native Web
// webpack.config.js
const ModuleFederationPlugin = require('@module-federation/webpack');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        'user-app': 'userApp@http://localhost:3001/remoteEntry.js',
        'product-app': 'productApp@http://localhost:3002/remoteEntry.js',
      },
    }),
  ],
};

// Lazy load micro-frontends
const UserApp = React.lazy(() => import('user-app/App'));
const ProductApp = React.lazy(() => import('product-app/App'));

function ShellApp() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen 
          name="Users" 
          component={() => (
            <Suspense fallback={<LoadingSpinner />}>
              <UserApp />
            </Suspense>
          )} 
        />
        <Stack.Screen 
          name="Products" 
          component={() => (
            <Suspense fallback={<LoadingSpinner />}>
              <ProductApp />
            </Suspense>
          )} 
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Conclusion

React Native Web enables true universal app development, allowing you to share up to 95% of your code across mobile and web platforms. By following the best practices outlined in this guide, you can build performant, accessible, and maintainable applications that provide consistent user experiences across all platforms.

Key Takeaways:
  • ✅ Use React Native Web for maximum code sharing
  • ✅ Optimize for web-specific performance considerations
  • ✅ Implement responsive design patterns
  • ✅ Handle platform-specific code gracefully
  • ✅ Test across all target platforms
  • ✅ Consider PWA features for enhanced web experience

As React Native Web continues to evolve, it's becoming the go-to solution for teams looking to build cross-platform applications efficiently. Start with a small project to get familiar with the ecosystem, then gradually adopt it for larger applications as your team gains experience.

🚀 Ready to catch UI issues before your users do?

Use Viewlytics to automatically capture and analyze your app's UI across real devices. Our AI-powered platform helps you identify visual bugs, layout issues, and inconsistencies before they impact user experience.

Start UI Testing with Viewlytics
logo

2025 © Viewlytics. All rights reserved.