Skip to main content

React Native Overview

Complete guide to React Native project setup, configuration, and development workflow.

Overview

This guide covers React Native project setup from initial scaffolding through build configuration. React Native enables cross-platform mobile development with JavaScript/TypeScript while maintaining native performance for critical banking features like biometric authentication and secure storage.

React Native works by running JavaScript/TypeScript logic and native UI rendering in coordinated runtimes. In modern React Native (0.84+), the New Architecture (Fabric + TurboModules + JSI) is the standard model for communication between JS and native code. This architecture allows developers to write business logic once in JavaScript/TypeScript while leveraging platform-specific UI components that provide native look, feel, and performance.

The framework compiles to truly native applications, not web views. When you render a <View> component, React Native creates an actual UIView on iOS or android.view.View on Android. This is fundamentally different from hybrid frameworks like Cordova that wrap web content in a WebView. The result is applications that perform like native apps because they are native apps, with JavaScript controlling the logic rather than Swift/Kotlin.

For banking applications, this architecture provides the perfect balance: shared business logic (payment processing, validation, offline sync) written once in TypeScript, while security-critical components (biometric authentication, secure storage, certificate pinning) leverage native iOS and Android APIs through either pre-built libraries or custom native modules. See our React Native Security guide for details on integrating native security features.

New Architecture in Practice

  • Fabric: New rendering system that improves consistency between iOS and Android behavior and enables better scheduling with React concurrency.
  • TurboModules: Faster, lazy-loaded native modules so startup time is not dominated by loading every bridge module up front.
  • JSI: JavaScript Interface enabling direct JS/native interaction without the old serialized bridge bottleneck.

For production apps, validate that key dependencies are New Architecture-compatible before upgrading React Native. Incompatibilities usually appear in older native modules, not in app code.


Core Principles

  1. React Native CLI over Expo: Full native module access for banking SDKs
  2. TypeScript Required: Type safety prevents runtime errors in production
  3. Functional Components: Hooks-based architecture, no class components
  4. Offline-First: Design for unreliable network conditions from the start
  5. Native Parity: Support iOS and Android equally with platform-specific code when needed
  6. Performance First: 60 FPS target, optimized builds, fast startup time
  7. Security Hardened: Secure storage, certificate pinning, ProGuard/obfuscation enabled

React Native Development Lifecycle


Project Setup

React Native CLI provides full access to native code, allowing you to integrate banking SDKs, implement custom native modules, and configure build settings precisely. Unlike Expo Go, which runs in a managed environment, React Native CLI generates actual iOS (.xcodeproj) and Android (build.gradle) projects that you control completely.

Banking applications require this control to:

  • Configure ProGuard/R8 obfuscation rules for Android to protect code from reverse engineering
  • Set up certificate pinning in native network security configurations to prevent man-in-the-middle attacks
  • Integrate biometric libraries that require native permissions and entitlements
  • Access Keychain (iOS) and Keystore (Android) directly for secure credential storage
# Prerequisites
node --version # 20+ LTS
npm --version # 10+

# Create new React Native project with TypeScript
npx react-native@latest init PaymentApp --template react-native-template-typescript

cd PaymentApp

# Install essential dependencies
npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
npm install react-native-screens react-native-safe-area-context
npm install @tanstack/react-query
npm install zustand
npm install react-native-keychain
npm install @react-native-async-storage/async-storage
npm install @react-native-community/netinfo
npm install react-native-fast-image

# Development dependencies
npm install --save-dev @testing-library/react-native jest-expo
npm install --save-dev @types/react @types/react-native
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier

# Install iOS pods (macOS only)
cd ios && pod install && cd ..

After running these commands, you'll have a fully configured React Native project with native iOS and Android folders. The iOS folder contains Xcode project files where you'll configure signing certificates, entitlements (for biometrics, keychain access), and Info.plist settings. The Android folder contains Gradle build files where you'll set up ProGuard, configure network security, and manage permissions in AndroidManifest.xml. Both platforms' native code is directly accessible for customization, unlike Expo's managed workflow where native code is abstracted away.

Expo (For Rapid Prototyping Only)

# Create Expo project
npx create-expo-app@latest PaymentApp --template blank-typescript

cd PaymentApp

# Install additional dependencies
npx expo install @react-navigation/native @react-navigation/native-stack
npx expo install react-native-screens react-native-safe-area-context
Expo Limitations

Expo Go does not support many native banking SDKs (biometric authentication with custom UI, certificate pinning, some secure storage modules). For production banking apps, use React Native CLI or Expo with a Custom Development Client + EAS Build when native modules are required.

PackageVersionReason
React Native0.84+New Architecture default, improved startup/runtime performance
React19.xLatest React APIs and compiler-era optimizations
TypeScript5.9+Latest type-system improvements and tooling performance
Node.js22 LTS+Current LTS baseline for tooling and CI
React Navigation7.xCurrent major with improved TS ergonomics
React Query5.xServer state management, caching
Zustand5.xLightweight client state management

Project Structure

payment-app/
|-- src/
| |-- components/
| | |-- common/
| | `-- domain/
| |-- screens/
| | |-- auth/
| | |-- payments/
| | `-- profile/
| |-- navigation/
| |-- services/
| | |-- api/
| | |-- auth/
| | `-- storage/
| |-- store/
| |-- hooks/
| |-- utils/
| |-- types/
| |-- assets/
| |-- config/
| `-- App.tsx
|-- android/
|-- ios/
|-- __tests__/
|-- tsconfig.json
|-- metro.config.js
`-- package.json

This structure is organized by feature boundaries and runtime responsibilities. Keep UI components, navigation, data access, and state management separated so teams can evolve layers independently without creating cross-cutting coupling.

Architecture Layers


Development Workflow

Metro Bundler Configuration

Metro is React Native's JavaScript bundler that transforms and bundles your code for deployment. Think of it like Webpack for React Native, but optimized specifically for mobile development patterns. Metro performs several crucial tasks: transpiling TypeScript/JSX to JavaScript, resolving module imports, bundling code into a single JavaScript file, and serving that bundle during development with Fast Refresh support.

The inlineRequires optimization transforms your code to lazy-load modules only when first accessed instead of loading all modules at app startup. For example, if you have a rarely-used transaction history export feature, that code won't be loaded until the user actually navigates to that screen. This dramatically reduces initial bundle evaluation time, getting users to the login screen faster - critical for banking applications with large codebases where slow startup drives user abandonment.

The asset extensions configuration tells Metro which file types to treat as static assets (images, fonts) versus source code. When Metro encounters a .png import, it processes it as an image asset, generating appropriate platform-specific resource handling. For .ts files, it runs the TypeScript compiler and then bundles the resulting JavaScript.

// metro.config.js
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

/**
* Metro configuration
* Banking apps need optimized bundling for performance
*/
const config = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true, // Improve startup time by lazy-loading modules
},
}),
},
resolver: {
// Support for SVG and other assets
assetExts: ['png', 'jpg', 'jpeg', 'svg', 'gif', 'webp'],
sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'cjs'],
},
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

Learn more about bundle optimization in our React Native Performance guide, which covers code splitting, reducing bundle size, and profiling Metro build performance.

TypeScript Configuration

// tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"lib": ["es2019"],
"allowJs": true,
"jsx": "react-native",
"strict": true, // Enable all strict checks
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"baseUrl": "./src",
"paths": {
"@components/*": ["components/*"],
"@screens/*": ["screens/*"],
"@services/*": ["services/*"],
"@hooks/*": ["hooks/*"],
"@utils/*": ["utils/*"],
"@types/*": ["types/*"],
"@assets/*": ["assets/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}

Platform-Specific Code

File Extensions

src/components/
|-- Button.tsx # Shared code
|-- Button.ios.tsx # iOS-specific implementation
`-- Button.android.tsx # Android-specific implementation

Platform API

// utils/platform.ts
import { Platform } from 'react-native';

export const isIOS = Platform.OS === 'ios';
export const isAndroid = Platform.OS === 'android';

// Use Platform.select for inline differences
export const shadowStyle = Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
},
android: {
elevation: 5,
},
});

// Platform-specific dimensions
export const statusBarHeight = Platform.select({
ios: 44,
android: 24,
});

Build Configuration

Development vs Production

Environment Variables

# .env.development
API_URL=https://api-dev.bank.com
API_TIMEOUT=30000
ENABLE_LOGGING=true
ENVIRONMENT=development
# .env.production
API_URL=https://api.bank.com
API_TIMEOUT=10000
ENABLE_LOGGING=false
ENVIRONMENT=production
// config/env.ts
import Config from 'react-native-config';

export const ENV = {
API_URL: Config.API_URL || '',
API_TIMEOUT: parseInt(Config.API_TIMEOUT || '10000', 10),
ENABLE_LOGGING: Config.ENABLE_LOGGING === 'true',
ENVIRONMENT: Config.ENVIRONMENT || 'development',
} as const;

Common Mistakes

Not Using TypeScript Strict Mode

// BAD: Loose TypeScript
const formatAmount = (amount) => { // Implicit any
return `$${amount}`;
};
// GOOD: Strict TypeScript
const formatAmount = (amount: number): string => {
return `$${amount.toFixed(2)}`;
};

Not Handling Platform Differences

// BAD: Assumes all platforms are the same
<View style={{ elevation: 5 }}> {/* Won't work on iOS */}
<Text>Card</Text>
</View>
// GOOD: Platform-specific styles
import { Platform, StyleSheet } from 'react-native';

const styles = StyleSheet.create({
card: {
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 3.84,
},
android: {
elevation: 5,
},
}),
},
});

Ignoring Metro Bundler Optimization

// BAD: No optimization
const config = {};
module.exports = config;
// GOOD: Optimized Metro config
const config = {
transformer: {
getTransformOptions: async () => ({
transform: {
inlineRequires: true, // Faster startup
},
}),
},
};

Code Review Checklist

Project Setup

  • TypeScript strict mode enabled in tsconfig.json
  • React Native CLI used for production banking apps (not Expo Go)
  • All required dependencies installed (navigation, state management, secure storage)
  • Native linking completed (iOS pods, Android dependencies)
  • .env files configured for different environments

Project Structure

  • Clear separation of concerns (components, screens, services, hooks)
  • Shared components in common/ directory
  • Domain components separate from generic components
  • Services layer abstracts API and native modules
  • Types directory contains all TypeScript interfaces

Platform Support

  • Platform-specific code uses .ios.tsx and .android.tsx when needed
  • Platform.select used for inline platform differences
  • Styles handle both platforms (shadow vs elevation)
  • Safe area insets respected on both platforms
  • Status bar configured correctly for each platform

Build Configuration

  • Metro bundler optimized (inlineRequires enabled)
  • Environment variables configured via react-native-config
  • Production builds have minification and obfuscation
  • Source maps disabled in production
  • Dev menu disabled in production builds

Banking-Specific

  • Secure storage configured (react-native-keychain)
  • Network detection implemented (@react-native-community/netinfo)
  • Offline-first architecture planned from start
  • Biometric authentication library included if needed
  • Certificate pinning will be implemented in API client

Further Reading

React Native Framework Guidelines

Cross-Platform Guidelines

External Resources


Summary

Key Takeaways

  1. React Native CLI - Use for production banking apps, not Expo Go
  2. TypeScript strict mode - Required for type safety and fewer runtime errors
  3. Structured project - Clear separation: components, screens, services, hooks
  4. Platform-aware - Handle iOS/Android differences with Platform API
  5. Optimized Metro - Enable inlineRequires for faster startup
  6. Environment config - Separate dev/prod configurations
  7. Offline-first setup - Plan architecture from project start
  8. Secure by default - Include secure storage and biometric libraries
  9. Testing ready - Include Testing Library and Jest configuration
  10. Type-safe navigation - Define route params and screen props upfront

Next Steps: Review React Native Navigation to implement type-safe navigation with React Navigation, then explore React Native UI for component architecture and styling patterns.