React Native: Cross-Platform Mobile Development
React Native is a framework for building mobile applications using JavaScript and React. Created by Facebook and released as open source in 2015, it changed mobile development by allowing developers to write truly native mobile apps using web technologies. Instead of compiling to web views (like hybrid frameworks), React Native renders native UI components — your app looks and feels like a real native app, but you write it with React.
According to the React Native documentation, the framework has undergone major architectural changes with the New Architecture (Fabric renderer and TurboModules) improving performance and interoperability. Facebook uses React Native in production for Facebook and Instagram. Shopify, Uber Eats, Pinterest, Discord, and thousands of other apps rely on React Native. The framework has a mature ecosystem with thousands of libraries and a strong community.
Setting Up React Native
You have two main approaches to starting a React Native project. The React Native CLI provides full access to native modules and is the standard approach. Expo abstracts native setup and provides over-the-air updates, an extensive SDK, and managed build services:
# React Native CLI
npx react-native init MyApp
cd MyApp
npx react-native run-ios # Requires Xcode
npx react-native run-android # Requires Android Studio
# Expo
npx create-expo-app MyApp
cd MyApp
npx expo startExpo is recommended for most new projects. The Expo SDK now provides access to most native APIs through a consistent JavaScript interface, and EAS Build handles custom native modules when needed. Expo’s development builds combine the managed workflow with full native module support.
Core Components
React Native provides a set of core components that map directly to native UI elements. Understanding these components is essential for building any React Native application.
View is the most fundamental component — a container that supports layout with flexbox, styling, touch handling, and accessibility. It maps to UIView on iOS and android.view.View on Android.
Text displays text content. Unlike React for the web, text must always be wrapped in a Text component — you cannot put text directly inside a View. This constraint enables efficient text layout and accessibility.
ScrollView provides a scrollable container. Use it when content may overflow the screen. FlatList renders a scrollable list efficiently — it only renders items that are currently visible, recycling off-screen elements. For even better performance with large datasets, consider Shopify’s FlashList, which is API-compatible with FlatList but renders 10x faster:
<FlatList
data={items}
renderItem={({ item }) => <Text>{item.name}</Text>}
keyExtractor={item => item.id}
/>TextInput allows the user to enter text. Image displays images from network, local, or static sources. TouchableOpacity, TouchableHighlight, and Pressable provide touch interaction for custom buttons. Pressable is the preferred option for new code due to its flexible state handling.
Styling with Flexbox
React Native uses a subset of CSS. Styles are defined as JavaScript objects using camelCase properties. The StyleSheet.create() method validates styles and improves performance by creating immutable style objects:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#333',
},
---);Layout in React Native uses flexbox, with flexDirection defaulting to column (unlike the web’s row default). This mobile-first default matches the vertical layout pattern common in mobile apps. Use justifyContent, alignItems, and alignSelf for precise positioning. The React Native documentation provides a complete flexbox reference with platform-specific behavior notes.
Navigation
Navigation in React Native is handled by libraries — the framework does not include a built-in navigation solution. React Navigation is the most popular and well-maintained choice:
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
---React Navigation supports stack navigation (push/pop transitions), bottom tabs, material top tabs, drawer navigation, and complex nested patterns. The navigation state can be persisted for seamless app restart. For deep linking, React Navigation provides a linking configuration object that maps URL paths to screen names.
State Management
Local state uses React’s useState and useReducer hooks. For global state, choose based on app complexity:
The Context API works well for medium-sized apps with a few shared values like authentication state and theme preferences:
const AuthContext = createContext();
function App() {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider value={{ user, setUser }}>
<MainApp />
</AuthContext.Provider>
);
---Redux Toolkit provides predictable state management with middleware support for side effects, and is the standard choice for larger apps with complex state:
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => { state.value += 1; },
},
---);Zustand and Jotai are simpler alternatives to Redux that have gained popularity for their minimal boilerplate. Zustand’s API is particularly straightforward — no providers, no action types, just hooks.
The New Architecture
React Native’s New Architecture represents a fundamental improvement to the framework. The Fabric renderer replaces the old ShadowTree with a new rendering pipeline that allows synchronous layout and direct communication between JavaScript and native threads. TurboModules replace the bridge for native module access, enabling lazy loading and type-safe native module interfaces.
The Hermes engine is the recommended JavaScript engine for React Native. It precompiles JavaScript to bytecode at build time, reducing startup time by 30-50% and decreasing memory usage. Enable Hermes in your project configuration:
# android/app/build.gradle
project.ext.react = [
enableHermes: true
]
# ios/Podfile
hermes_enabled = trueNetworking and Data Fetching
React Native supports the standard fetch API and the XMLHttpRequest API for networking. For production apps, use axios for interceptors and request cancellation, or react-query for automatic caching, background refetching, and optimistic updates. React Native’s networking layer runs on the native thread, so network requests do not block the JavaScript thread:
import axios from 'axios';
async function fetchUser(userId) {
const response = await axios.get(`/api/users/${userId}`);
return response.data;
---For real-time communication, WebSockets work natively in React Native. Libraries like Socket.IO and react-native-push-notification handle persistent connections efficiently.
Platform-Specific Code
Use the Platform module for simple platform differences:
import { Platform } from 'react-native';
const styles = StyleSheet.create({
container: {
paddingTop: Platform.OS === 'ios' ? 44 : 0,
},
---);Use .ios.js and .android.js file extensions for entirely different implementations. React Native automatically selects the correct file based on the platform. For platform-specific behavior within a single file, use Platform.select() which returns platform-specific values from a configuration object.
FAQ
Should I use Expo or React Native CLI?
Use Expo for most new projects. Expo SDK now provides access to most native APIs, and EAS Build handles custom native modules. Use React Native CLI only when you need a specific native module or configuration that Expo does not support, such as custom native code that requires direct integration.
How does React Native performance compare to native?
React Native performance is near-native for most user interfaces. The JavaScript-to-native bridge adds overhead for complex animations and heavy computation. Use the Hermes engine, Reanimated 2, and native modules to optimize performance-critical paths. With the New Architecture, the bridge overhead is significantly reduced.
Can I use React Native for production apps?
Yes. React Native powers production apps for Facebook, Instagram, Shopify, Uber Eats, Pinterest, Discord, and thousands more. The framework is mature, well-maintained, and suitable for large-scale applications. The New Architecture addresses many historical performance concerns.
How do I debug React Native apps?
Use Flipper, the official React Native debugging tool. It provides JavaScript debugging, network inspection, layout inspection, crash reporting, and React DevTools integration. For quick iteration, use React Native’s fast refresh for instant feedback on code changes.
How do I handle app state and lifecycle in React Native?
React Native provides the AppState module for detecting foreground, background, and inactive states. Use useEffect with an AppState subscription to react to app lifecycle changes:
useEffect(() => {
const subscription = AppState.addEventListener('change', state => {
if (state === 'active') refreshData();
});
return () => subscription.remove();
---, []);This pattern is essential for saving state when the app backgrounds, similar to Flutter’s WidgetsBindingObserver.
What is React Native’s relationship with Expo?
Expo is a framework built on top of React Native. It provides a managed development environment with an extensive SDK, build services (EAS), and over-the-air updates. Expo is maintained by Expo.dev and has become the recommended starting point for most React Native projects. The Expo team contributes significantly to React Native itself.
Conclusion
React Native is a powerful, proven choice for cross-platform mobile development. One JavaScript or TypeScript codebase produces native iOS and Android applications. The ecosystem is mature, the developer experience is excellent (hot reloading, React DevTools), and you can always drop down to native code when needed. Combined with Expo for simplified tooling and the New Architecture for improved performance, React Native is the most productive way to build mobile applications for most teams.
For advanced topics, see the React Native Performance Guide and Mobile App Testing Guide.