To help with mobile development, there are some areas to make note of while making the web version React. It will allow more reusable code when starting the React Native project

  • Keep business logic independent : avoid putting it inside pages/
  • Separate hooks, services, and state : these are fully reusable in React Native
  • Use atomic components : reusable components that don’t depend on DOM APIs
  • Limit CSS-in-JS to web-only components : since React Native uses StyleSheet/
  • Avoid Next.js-specific APIs in your core logic : SSR/SSG code stays isolated

Sample Structure to Make Next.js Project, Mobile-Ready

Separate reusuable code from web-specific code to copy & paste as much as possible over to the React Native project

my-app/
├── app/                         # Next.js app router (if using /app directory)
│   ├── layout.jsx               # Web layout only
│   ├── page.jsx                 # Home page( High-level pages can map directly to RN screens)
│   ├── about/
│   │   └── page.jsx             # About page( High-level pages can map directly to RN screens)
│   ├── gallery/
│   │   └── page.jsx
│   └── api/                     # Next.js API routes (web-only)
│
├── src/
│   ├── components/              # UI components (shared between Web & Mobile when possible)
│   │   ├── common/              # Pure, reusable components (✅ transferable)
│   │   │   ├── Button.jsx
│   │   │   ├── ImageCard.jsx
│   │   │   └── Loader.jsx
│   │   └── web/                 # Web-only components (❌ not reusable in RN)
│   │       ├── Navbar.jsx
│   │       ├── Footer.jsx
│   │       └── NextImage.jsx
│   │
│   ├── hooks/                   # Reusable React hooks (✅ transferable)
│   │   ├── useFetch.jsx
│   │   ├── useAuth.jsx
│   │   └── useDebounce.jsx
│   │
│   ├── services/                # API calls & data fetching (✅ transferable)
│   │   ├── apiClient.jsx         # Axios or Fetch wrapper
│   │   ├── imageService.jsx
│   │   └── authService.jsx
│   │
│   ├── state/                   # State management (✅ transferable)
│   │   ├── store.jsx            # Redux / Zustand / Recoil setup
│   │   ├── imageSlice.jsx
│   │   └── authSlice.jsx
│   │
│   ├── utils/                   # Pure helper functions (✅ transferable)
│   │   ├── formatDate.jsx
│   │   ├── debounce.jsx
│   │   └── paginate.jsx
│   │
│   └── config/                  # Environment config (✅ transferable)
│       ├── env.jsx
│       └── constants.jsx
│
├── public/                      # Static images & assets (web only)
│   ├── images/                  # accessed from root (/images/*)
│   └── sitemap.xml              # good for SEO (/sitemap.xml)
│   └── robots.txt               # accessed from root (/robots.txt)
├── store.js
│
├── styles/                      # Web-only styles (❌ not used in RN)
│   ├── globals.css
│   ├── theme.jsx
│   └── variables.css
│
├── package.json
├── tsconfig.json
└── next.config.js

Sample Monorepo Structure with TurboRepo

my-monorepo/
├── apps/
│   ├── mobile/					# where the MOBILE expo app will be
│   │   ├── assets/				# holds the assets for MOBILE
│   │   ├── app/
│   │   │   ├── _layout.js		# Root layout for expo-router (like the layout.js of Next)
│   │   │   ├── index.js		# mobile Home page (/)
│   │   │   └── about.js		# mobile About page (/about)
│   │   ├── app.json				# MOBILE manifest file
│   │   ├── babel.config.js			# MOBILE babel config file
│   │   ├── metro.config.js			# MOBILE metro bundler config file
│   │   └── package.json 			# MOBILE scripts and dependencies
│   └── web/					# where the WEB next.js app will be
│       ├── public/				# holds static assets for WEB
│       │   ├── _layout.js
│       │   ├── sitemap.xml     # good for SEO (/sitemap.xml)
│       │   └── robots.txt      # accessed from root (/robots.txt)
│       ├── app/
│       │   ├── page.js			# Home page (/) - normal entry point
│       │   ├── layout.js		# Optional Global Layout - entry point if file exist
│       │   ├── global.css
│       │   └── About/
│       │       └── page.js		# web About page (/about)
│       ├── jsconfig.js				# WEB compiler options: import alias
│       ├── next.config.js			# WEB next.js bundler config file
│       └── package.json			# WEB scripts and dependencies 
├── shared/						# Codes that will be shared between Next and Expo
│   ├── assets/
│   └── components/
├── package.json				# turborepo and root dependencies, scripts, and overrides
├── turbo.json					# turborepo config file
└── eslint.config.mjs			# ESLint config file

Shared Components & Web-Only Components

Shared components will be React components that does NOT render JSX element and is NOT dependent on Next.js (like function that handle routing)

Web-only components will only render JSX elements, is where CSS modules are imported, or uses Next.js dependencies like routing

All React Native components are client-side

// JSX
export default function SharedComponent(){
    // Fetch data, handle states/hooks, event handlers
    return <WebComponent />
}

export default function WebComponent(props) {
    return (
        <div>
            <button onClick={props.onClick}/>
        </div>
    )
}

What React Native will Need

  • Redo routing on React Native using React Navigation or Expo Router for expo app
  • Remake the UI components that makes use of JSX
    • Replace the HTML elements with React Native/ react-native-web counterpart
  • Redo styling, because React Native does not support .css files