Skip to main content

Turning a Web App into Mobile: Migrating to React Native

· 8 min read
Engineering Team

Migrate a web app to React Native by sharing domain logic and API clients while rebuilding navigation, accessibility, storage, and interaction for native platforms. This revised guide emphasizes supported APIs, production tradeoffs, and an upgrade-friendly path without tying the advice to a calendar year.

Turning a Web App into Mobile: Migrating to React Native

Modern implementation baseline

Migrate a web app to React Native by sharing domain logic and API clients while rebuilding navigation, accessibility, storage, and interaction for native platforms.

Use TypeScript, the New Architecture, supported public APIs, and libraries that publish an explicit compatibility policy. Prefer framework-managed native dependencies when that reduces upgrade risk, and verify behavior in release builds on both platforms.

  • Inventory reusable logic separately from DOM-based UI.
  • Build one vertical mobile workflow before broad migration.
  • Design offline, deep-link, keyboard, and permission behavior explicitly.

Production checklist

  • Test on representative Android and iOS devices, not only simulators.
  • Profile startup, interaction latency, memory, and network failure states.
  • Keep native dependencies compatible with the active React Native release line.

Authoritative references

Why migrate to React Native?

React Native remains a top choice for cross-platform development due to:

  • Performance Boosts: Hermes, the standard JavaScript engine in supported React Native releases, improves startup and memory behavior, ideal for web-to-mobile transitions.
  • Code Reusability: Share up to 80% of your JavaScript codebase from web (e.g., React) with minimal adjustments.
  • Modern Ecosystem: Integration with TypeScript, React Navigation 7, and Reanimated 3 ensures a future-proof stack.
  • Community Support: Active updates and a robust plugin ecosystem keep React Native relevant for startups and enterprises.

Prerequisites

Before starting, ensure you have:

  • Node.js 20.x (LTS) and npm 10.x installed.
  • React Native CLI or the current stable Expo SDK set up.
  • A web app built with React 18.x (or a similar framework like Next.js).
  • Basic knowledge of JavaScript/TypeScript and mobile development concepts.

Step-by-Step Migration Process

1. Assess Your Web App

What to Evaluate

  • Component Structure: Identify reusable React components (e.g., buttons, forms).
  • State Management: Check if you use Context API, Redux Toolkit, or Zustand.
  • APIs and Data: Ensure your REST or GraphQL endpoints are mobile-friendly (e.g., handle offline data with WorkManager).
  • UI/UX: Note web-specific styles (e.g., CSS) that need adaptation for mobile screens.

Action

  • Document your app’s architecture and list components for reuse. Use tools like Bit to extract reusable UI components.

2. Set Up a New React Native Project

Using React Native CLI

  1. Initialize a new project:
    npx @react-native-community/cli@latest init MobileApp
  2. Navigate to the project:
    cd MobileApp
  1. Create a project:
    npx create-expo-app@latest MobileApp --template blank-typescript
  2. Start the app:
    npx expo start
  • Hermes Compatibility: No extra configuration is needed in app.json for Expo 51+ as Hermes is enabled by default:
    "expo": {
    "jsEngine": "hermes"
    }

Why Expo?

Expo 51 simplifies native module integration and includes Hermes, reducing setup time. Dopebase offers Expo-compatible templates to jumpstart this step.

3. Migrate Reusable Code

Transfer Components

  • Copy reusable React components (e.g., Button, Input) from your web app to the src/components folder.
  • Update imports to use React Native’s core components (e.g., replace div with View, span with Text).
  • Example:
    // Web: src/components/Button.js
    import React from 'react';
    import './Button.css';

    const Button = ({ children, onClick }) => (
    <button className="btn" onClick={onClick}>{children}</button>
    );

    // Mobile: src/components/Button.tsx
    import React from 'react';
    import { TouchableOpacity, Text, StyleSheet } from 'react-native';

    const Button = ({ children, onClick }) => (
    <TouchableOpacity style={styles.button} onPress={onClick} accessible={true}>
    <Text style={styles.text}>{children}</Text>
    </TouchableOpacity>
    );

    const styles = StyleSheet.create({
    button: { padding: 10, backgroundColor: '#007AFF', minWidth: 48, minHeight: 48 }, // 48x48 touch target for accessibility
    text: { color: '#fff', textAlign: 'center' },
    });

    export default Button;

Adapt State Management

  • Context API: Migrate directly with minor adjustments for mobile lifecycle events.
  • Redux Toolkit: Install @reduxjs/toolkit and react-redux:
    npm install @reduxjs/toolkit react-redux
    Configure a store and reuse reducers from your web app.
  • Zustand: Works out of the box with no platform-specific issues. Continue using your stores as-is if they’re not tightly coupled to DOM APIs. Example:
    import create from 'zustand';

    const useStore = create((set) => ({
    count: 0,
    increment: () => set((state) => ({ count: state.count + 1 })),
    }));

    export default useStore;

4. Handle Styling and Layout

Replace CSS with StyleSheet

  • Convert web CSS to React Native’s StyleSheet. Use flexbox for responsive layouts:
    import { StyleSheet } from 'react-native';

    const styles = StyleSheet.create({
    container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    },
    });

Use Tailwind CSS (Optional)

  • Integrate react-native-tailwindcss for a web-like styling experience:
    npm install react-native-tailwindcss
  • Example:
    import tw from 'react-native-tailwindcss';

    const App = () => <View style={tw`flex-1 justify-center items-center bg-gray-100`}>Hello</View>;

Accessibility Note

Ensure touch targets are at least 48x48 dp for accessibility, as required by React Native guidelines. Adjust button styles accordingly (see example above).

5. Implement Navigation

Use React Navigation 7

  1. Install dependencies:
    npm install @react-navigation/native @react-navigation/native-stack
    npx expo install react-native-screens react-native-safe-area-context
  2. Set up a stack navigator:
    import { NavigationContainer } from '@react-navigation/native';
    import { createNativeStackNavigator } from '@react-navigation/native-stack';

    const Stack = createNativeStackNavigator();

    const App = () => (
    <NavigationContainer>
    <Stack.Navigator initialRouteName="Home">
    <Stack.Screen name="Home" component={HomeScreen} />
    <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
    </NavigationContainer>
    );

    export default App;

Deep Linking (Optional)

If your web app uses routing, set up deep linking:

<NavigationContainer linking={linking}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>

const linking = {
prefixes: ['yourapp://'],
config: { screens: { Home: '' } },
};

6. Test and Optimize

Run on Emulators

  • For Android:
    npx react-native run-android
  • For iOS:
    npx react-native run-ios

Optimize with Hermes

  • Hermes is the standard engine in supported React Native projects. Verify the generated native build configuration when migrating an older app:
    project.ext.react = [
    enableHermes: true,
    ]

Debugging

  • React Native CLI: Use React Native DevTools and native platform profilers for debugging:
    npm install --save-dev @react-native-community/flipper
  • Expo: Use Expo DevTools during development and a privacy-reviewed observability service for release builds:
    npm install @sentry/react-native

7. Deploy to App Stores

For React Native CLI

  • Android: Create a signed APK/AAB:
    cd android && ./gradlew bundleRelease
  • iOS: Archive in Xcode and submit via App Store Connect.

For Expo Managed Workflow

  • Use EAS Build:
    npx eas build --platform android
    npx eas build --platform ios
  • Alternatively, with classic Expo build:
    npx expo build:android
    npx expo build:ios

Dopebase Templates

Dopebase provides pre-configured templates with CI/CD setups (e.g., Fastlane) to streamline deployment. Check instamobile.io for React Native options.

Current best practices

  • Leverage TypeScript: Use TypeScript for type safety across web and mobile codebases.
  • Optimize Images: Use react-native-fast-image for efficient loading. Additionally:
    • Integrate react-native-svg for scalable vector graphics:
      npm install react-native-svg
    • Load images from CDNs like Cloudinary for dynamic content.
  • Enable Dark Mode: Implement theming with Appearance API:
    import { useColorScheme } from 'react-native';

    const App = () => {
    const colorScheme = useColorScheme();
    const theme = colorScheme === 'dark' ? darkStyles : lightStyles;
    return <View style={theme.container} />;
    };
  • Platform-Specific Behaviors: Use expo-device to detect device capabilities:
    npm install expo-device
    import * as Device from 'expo-device';

    if (Device.osName === 'iOS') { /* iOS-specific logic */ }
  • Consistent Layouts: Use react-native-responsive-dimensions for adaptive designs:
    npm install react-native-responsive-dimensions

Conclusion

Migrating a web app to mobile with React Native is a strategic move to reach wider audiences with minimal rework. By reusing your React components, adopting modern tools like Hermes, React Navigation 7, and optimizing for accessibility and performance, you can launch a native app efficiently. For a head start, Dopebase offers production-ready templates at instamobile.io and instaflutter.com, tailored for React Native and Flutter. Follow us on X or Facebook for more migration tips and join our community to share your journey!

Hashtags

#Dopebase #MobileApps #ReactNative #WebToMobile #AppDevelopment #Expo #Hermes #TypeScript #ReactNavigation #Flutter #Tech2025

Additional Resources