React 121 ⚛️ Cross-Platform Mobile Apps with React Native Core
React Native is not React running in a browser. It is a framework that uses the React programming model to describe a native view tree, and at runtime it creates the actual platform views—UIView on iOS, android.view.View on Android—that the operating system renders. The JavaScript you write looks like React, but the primitives are different, and the rules of styling and layout are different, because the target is a mobile platform rather than a DOM.
This chapter covers the core of React Native as it exists in the framework’s documentation: the native component model, the foundational components that every application uses, and the styling and layout system that replaces CSS. It addresses the distinction between React DOM and React Native, the thread model that determines how JavaScript and native code interact, and the component categories that the framework provides. The final sections cover the library ecosystem and the constraints that make cross-platform development a matter of careful abstraction rather than automatic portability.
Key point: React Native components are not web elements. <View> is not a <div>, and <Text> is not a <p>. They are instructions to create platform-native views, and the styling rules that apply are the platform’s rules, not the browser’s.
Why React Native is not React for mobile
The rendering target. React DOM renders to the browser’s DOM. React Native renders to the native view tree of the platform. The react package is shared: components, hooks, state, context, and the reconciliation algorithm are identical. The react-dom package is replaced by react-native, which provides the primitives that map to native views . A React web application cannot be “pushed” to a mobile app by changing the import; the rendering primitives have different semantics, different styling rules, and different event models .
The component model. In Android and iOS development, a view is the basic rectangular building block of the UI. React Native exposes these views through components: <View> becomes ViewGroup on Android and UIView on iOS, <Text> becomes TextView and UITextView, and <Image> becomes ImageView and UIImageView . The components are “native components” because they are backed by the platform’s own views, which is why a React Native app looks and performs like a native app rather than a web app wrapped in a shell .
The styling system. React Native does not support CSS. There is no cascade, no selectors, and no stylesheets in the web sense. Styles are JavaScript objects, and the properties are a subset of CSS that maps to the platform’s layout system. Flexbox is the default layout model, but the defaults differ from CSS: flexDirection defaults to column, and the flex property works differently . A web developer’s CSS intuition is partially transferable, but the differences matter.
The thread model. React Native runs JavaScript on a separate thread from the native UI thread. The JavaScript thread executes the React components, processes state updates, and runs event handlers. The UI thread mounts native views, processes user input, and draws. The two threads communicate through the framework’s architecture—historically an asynchronous bridge, and in the modern architecture through JSI, Fabric, and TurboModules . The threading model is why a long-running JavaScript operation can freeze the UI, and why the framework provides InteractionManager and other scheduling APIs.
a. The core components and their native equivalents
React Native provides a set of core components that cover the basic building blocks of a mobile UI. The documentation lists them with their Android and iOS counterparts, and that table is the most precise description of what each component does .
| React Native | Android View | iOS View | Web Analog | Purpose |
|---|---|---|---|---|
<View> | ViewGroup | UIView | <div> | Layout container with flexbox, style, touch handling |
<Text> | TextView | UITextView | <p> | Display and nest strings, handle touch |
<Image> | ImageView | UIImageView | <img> | Display images |
<ScrollView> | ScrollView | UIScrollView | <div> | Generic scrolling container |
<TextInput> | EditText | UITextField | <input> | Text input via keyboard |
<Pressable> | — | — | <button> | Detect press interactions on children |
<FlatList> | — | — | — | Performant scrollable list |
<View> is the fundamental container. Every layout is built from nested views, and the flexbox model applies at each level. <Text> is the only component that can display raw text; a string placed directly inside a <View> produces an error. Text can be nested inside text, which is how inline styling and touch handling work . <Pressable> is the modern replacement for the older TouchableOpacity and TouchableHighlight components; it exposes press states through a style function and handles the interaction stages that a button needs.
<FlatList> and <SectionList> are the performant list components. Unlike <ScrollView>, which renders all its children at once, FlatList renders only the items currently visible on the screen, which makes it suitable for long lists . A list of a thousand items that renders all of them in a <ScrollView> will consume memory and time proportional to the list size; the same list in a <FlatList> consumes memory proportional to the visible window.
b. Styling, layout, and the flexbox defaults
React Native styles are objects passed to the style prop. The StyleSheet.create function is the conventional way to define them, though it is largely an identity function in modern React Native; its value is in validation and organization rather than performance .
import { View, Text, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 16,
backgroundColor: '#fff',
},
label: {
fontSize: 16,
fontWeight: '600',
color: '#333',
},
});
function Header() {
return (
<View style={styles.container}>
<Text style={styles.label}>Title</Text>
<Text style={styles.label}>Action</Text>
</View>
);
}
The layout differences from CSS are the source of most early confusion. flexDirection defaults to column, not row. The flex property takes a number, and flex: 1 means “take up the remaining space,” which is different from CSS’s flex: 1 shorthand. There are no percentage-based widths for every property; some accept percentages, some do not. The position property defaults to relative, and absolute positioning is relative to the parent view rather than the page . A web developer should read the Layout Props documentation before assuming that a CSS pattern will translate.
The style prop accepts an array of style objects, and later objects override earlier ones. This is the mechanism for conditional styling and for merging a base style with a variant style.
<View style={[styles.base, isActive && styles.active]} />
c. The library ecosystem and the cross-platform constraint
React Native’s core components cover the essentials, but an application needs navigation, state management, networking, storage, and device APIs. The framework does not prescribe these; it provides the primitives and leaves the rest to the ecosystem . The community maintains libraries for the common needs, and Expo provides a curated set that works across iOS, Android, and web .
The library selection process is different from web development. A package that works in a browser may depend on react-dom, the DOM, or Node.js APIs that React Native does not provide. react-select is built for the web and targets react-dom; rimraf is built for Node.js and interacts with the file system. Neither works in React Native. Libraries that use only JavaScript language features—lodash, for example—work in any environment . The React Native Directory is the first place to check; it lists libraries that are built specifically for React Native and allows filtering by platform .
The cross-platform constraint is the other half of the story. A component that renders correctly on iOS may break on Android because the platform’s native views behave differently. The SafeAreaView exists because the iPhone’s notch and home indicator require padding that Android does not. The Platform module allows platform-specific code, and the .ios.js / .android.js file extensions allow platform-specific implementations of the same module. The goal is not “write once, run anywhere” in the sense of identical output; it is “learn once, write anywhere” in the sense of sharing the programming model and the component tree while respecting the platform’s differences .
Complete Example Session
// ============================================
// PART 1: THE CORE COMPONENTS
// ============================================
// View, Text, Image, TextInput, Pressable.
// Each maps to a native view on the platform.
import React, { useState } from 'react';
import {
View,
Text,
Image,
TextInput,
Pressable,
StyleSheet,
FlatList,
SafeAreaView,
} from 'react-native';
// ============================================
// PART 2: THE LAYOUT
// ============================================
// Flexbox with React Native defaults:
// flexDirection: column, alignItems: stretch.
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#f5f5f5',
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
title: {
fontSize: 24,
fontWeight: '700',
},
input: {
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 8,
padding: 12,
marginBottom: 12,
backgroundColor: '#fff',
},
button: {
backgroundColor: '#007AFF',
padding: 14,
borderRadius: 8,
alignItems: 'center',
},
buttonText: {
color: '#fff',
fontWeight: '600',
},
item: {
padding: 16,
backgroundColor: '#fff',
borderRadius: 8,
marginBottom: 8,
},
});
// ============================================
// PART 3: THE COMPONENT
// ============================================
// A simple list with input and press handling.
export default function App() {
const [text, setText] = useState('');
const [items, setItems] = useState([]);
const addItem = () => {
if (!text.trim()) return;
setItems((prev) => [...prev, { id: Date.now().toString(), text }]);
setText('');
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>My List</Text>
</View>
<TextInput
style={styles.input}
value={text}
onChangeText={setText}
placeholder="Enter an item"
/>
<Pressable style={styles.button} onPress={addItem}>
<Text style={styles.buttonText}>Add</Text>
</Pressable>
<FlatList
data={items}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={styles.item}>
<Text>{item.text}</Text>
</View>
)}
/>
</SafeAreaView>
);
}
// ============================================
// PART 4: THE PLATFORM DIFFERENCE
// ============================================
// SafeAreaView handles the notch on iOS.
// Platform.select chooses per-platform values.
import { Platform } from 'react-native';
const platformStyle = Platform.select({
ios: { shadowColor: '#000', shadowOpacity: 0.1 },
android: { elevation: 2 },
default: {},
});
// ============================================
// PART 5: THE THREAD MODEL
// ============================================
// JavaScript runs on its own thread.
// Long operations block rendering.
// Use InteractionManager for deferral.
import { InteractionManager } from 'react-native';
function expensiveWork() {
InteractionManager.runAfterInteractions(() => {
// Runs after animations and gestures complete.
});
}
// ============================================
// PART 6: THE LIBRARY CONSTRAINT
// ============================================
// Check React Native Directory before installing.
// A web library that depends on react-dom will not work.
// npm install @react-native-community/netinfo
// (community library, built for React Native)
// ============================================
// PART 7: THE FLATLIST PERFORMANCE
// ============================================
// FlatList renders only visible items.
// ScrollView renders all children.
// For long lists, FlatList is required.
// ============================================
// PART 8: THE IMAGE COMPONENT
// ============================================
// Local images use require, remote images use uri.
// <Image source={require('./logo.png')} />
// <Image source={{ uri: 'https://example.com/img.png' }} />
// ============================================
// PART 9: THE TEXT NESTING
// ============================================
// Text can nest Text, but View cannot contain raw text.
// <Text>Hello <Text style={{ fontWeight: 'bold' }}>world</Text></Text>
// ============================================
// PART 10: THE FULL PICTURE
// ============================================
// React Native is React with native primitives.
// The component tree is the UI.
// The platform provides the views.
export default function Root() {
return <App />;
}
The ten parts build a complete React Native screen: the core components, the flexbox layout, the list, the platform differences, and the constraints. The pattern is consistent: the component tree is React, and the primitives are native.
Quick Reference
Core Components
| Component | Purpose | Platform Mapping |
|---|---|---|
<View> | Layout container | ViewGroup / UIView |
<Text> | Display text | TextView / UITextView |
<Image> | Display images | ImageView / UIImageView |
<ScrollView> | Scrolling container | ScrollView / UIScrollView |
<TextInput> | Text input | EditText / UITextField |
<Pressable> | Press handling | Touchable |
<FlatList> | Performant list | Recycler pattern |
Styling Differences
| CSS | React Native |
|---|---|
flex-direction: row | flexDirection: 'column' (default) |
display: flex | Always flex |
px units | Unitless numbers |
| Cascade/selectors | No cascade |
position: static | position: 'relative' (default) |
Component Categories
| Category | Examples |
|---|---|
| Basic | View, Text, Image, TextInput, Pressable, ScrollView |
| UI | Button, Switch |
| Lists | FlatList, SectionList |
| Android | BackHandler, DrawerLayoutAndroid, ToastAndroid |
| iOS | ActionSheetIOS |
| Others | ActivityIndicator, Alert, Animated, Dimensions |
Library Selection
| Check | Action |
|---|---|
| React Native Directory | Primary source |
| Platform compatibility | Filter by iOS, Android, Web |
| Dependencies | Avoid react-dom and Node.js APIs |
| Community vs Expo | Both are viable; Expo includes web support |
Best Practices
✅ Do This:
// Use FlatList for long lists.
<FlatList data={items} renderItem={renderItem} /> // ✅
// Use SafeAreaView for notch handling.
<SafeAreaView><Content /></SafeAreaView> // ✅
// Use Platform.select for platform-specific values.
Platform.select({ ios: {}, android: {} }) // ✅
// Use StyleSheet.create for organized styles.
const styles = StyleSheet.create({ ... }); // ✅
// Check React Native Directory before installing.
// Verify the library is built for React Native. // ✅
❌ Don’t Do This:
// Don't put raw text inside a View.
<View>Hello</View> // error: text must be in <Text> // ❌
// Don't use CSS patterns without checking.
flexDirection: 'row' // works, but default is column // ❌
// Don't use ScrollView for long lists.
<ScrollView>{items.map(...)}</ScrollView> // memory issue // ❌
// Don't install web libraries without checking.
npm install react-select // depends on react-dom // ❌
// Don't run long JavaScript operations on the main thread.
// It blocks the UI. // ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
Text outside <Text> | React Native requires explicit text components | Wrap in <Text> |
| Layout looks wrong | Flexbox defaults differ from CSS | Set flexDirection explicitly |
| Long list is slow | ScrollView renders all children | Use FlatList |
| Library does not work | Depends on react-dom or Node.js | Check React Native Directory |
| UI freezes | Long JavaScript operation | Use InteractionManager or split work |
| iOS/Android differences | Platform views behave differently | Use Platform.select and test on both |
Real-World Examples
1. View Container
<View style={{ flex: 1, padding: 16 }} />
2. Text Display
<Text style={{ fontSize: 18 }}>Hello</Text>
3. Image Source
<Image source={{ uri: 'https://example.com/img.png' }} />
4. TextInput
<TextInput value={text} onChangeText={setText} />
5. Pressable
<Pressable onPress={handlePress}><Text>Tap</Text></Pressable>
6. FlatList
<FlatList data={data} renderItem={({ item }) => <Text>{item.name}</Text>} />
7. StyleSheet
const styles = StyleSheet.create({ container: { flex: 1 } });
8. Platform Select
Platform.select({ ios: { color: 'blue' }, android: { color: 'green' } })
9. SafeAreaView
<SafeAreaView><Content /></SafeAreaView>
10. InteractionManager
InteractionManager.runAfterInteractions(() => { ... })
Visual
React DOM vs React Native
┌─────────────────────────────────────────────────────────┐
│ REACT (shared) │
│ components, hooks, state, context, reconciliation │
│ │ │
│ ┌────┴────┐ │
│ ▼ ▼ │
│ react-dom react-native │
│ (web) (mobile) │
│ │ │ │
│ ▼ ▼ │
│ DOM tree Native view tree │
│ <div> UIView / android.view.View │
│ <p> UITextView / TextView │
│ <img> UIImageView / ImageView │
│ │
│ The programming model is shared. │
│ The rendering primitives are not. │
└─────────────────────────────────────────────────────────┘
The Component-to-Native Mapping
┌─────────────────────────────────────────────────────────┐
│ JAVASCRIPT (your component) │
│ │
│ <View style={styles.container}> │
│ <Text>Hello</Text> │
│ </View> │
│ │ │
│ ▼ React Native renderer │
│ NATIVE VIEW TREE │
│ │
│ iOS: UIView │
│ └── UITextView │
│ │
│ Android: android.view.ViewGroup │
│ └── android.widget.TextView │
│ │
│ The platform renders its own views. │
│ There is no browser and no DOM. │
└─────────────────────────────────────────────────────────┘
The Flexbox Default
┌─────────────────────────────────────────────────────────┐
│ CSS DEFAULT │
│ flex-direction: row │
│ │
│ [ A ] [ B ] [ C ] ← horizontal │
│ │
│ ───────────────────────────────────────────────────── │
│ │
│ REACT NATIVE DEFAULT │
│ flexDirection: 'column' │
│ │
│ [ A ] │
│ [ B ] ← vertical │
│ [ C ] │
│ │
│ Set flexDirection: 'row' explicitly for horizontal. │
└─────────────────────────────────────────────────────────┘
The Thread Model
┌─────────────────────────────────────────────────────────┐
│ JAVASCRIPT THREAD │
│ React render, state, event handlers │
│ │ │
│ │ (modern architecture: JSI/Fabric) │
│ ▼ │
│ UI THREAD (main) │
│ Mount views, user input, drawing, animation │
│ │
│ Long JS operations block the JS thread. │
│ The UI thread can still respond to native input. │
│ But the JS-driven UI cannot update until JS is free. │
└─────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Core idea | React components rendering native views |
| Shared package | react |
| Rendering package | react-native (not react-dom) |
| Basic container | <View> → ViewGroup / UIView |
| Text | <Text> → TextView / UITextView |
| Image | <Image> → ImageView / UIImageView |
| Layout | Flexbox, flexDirection: 'column' default |
| Styling | StyleSheet.create, no CSS |
| Lists | FlatList for performance |
| Libraries | React Native Directory, avoid web-only packages |
Key takeaways:
- React Native is not React for the web. The
reactpackage is shared, butreact-domis replaced byreact-native. The rendering primitives are native views, not DOM elements . <View>and<Text>are the fundamentals. Every layout is built from nested views, and every string must be inside a<Text>. A string inside a<View>produces an error .- The flexbox defaults differ from CSS.
flexDirectioniscolumn, notrow. A web developer must read the layout documentation before assuming a CSS pattern translates . FlatListis not optional for long lists.ScrollViewrenders all children at once.FlatListrenders only the visible window, which makes the difference between a usable list and a memory problem .- The library ecosystem is curated, not universal. A package that works in the browser may depend on
react-domor Node.js APIs. React Native Directory is the first check, and the npm registry is the fallback . - The thread model determines performance. JavaScript runs on its own thread, and long operations block the JS-driven UI. The modern architecture (JSI, Fabric, TurboModules) improves the communication, but the constraint remains .
- “Learn once, write anywhere” is the correct framing. The programming model is shared, and the component tree is portable in structure, but the platform’s native views and behaviors require platform-specific attention .
Remember: React Native is a different rendering target for the same programming model. The components you write describe a native view tree, the styles you apply are the platform’s layout properties, and the libraries you install must be built for the mobile environment rather than the browser. The core components—View, Text, Image, TextInput, ScrollView, Pressable, FlatList—are the vocabulary, and the flexbox layout is the grammar. Learn the native mappings, respect the platform differences, and check the ecosystem before assuming that a web package will work. The result is an application that looks and performs like the platform it runs on, because it is built from the platform’s own views.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!