Conceptos básicos de React Native
10 ejemplos para que comiences con los Conceptos Fundamentales de React Native - 7 básicos y 3 intermedios.
Busca en todas las páginas de la documentación
10 ejemplos para que comiences con los Conceptos Fundamentales de React Native - 7 básicos y 3 intermedios.
Las apps de React Native necesitan un runtime nativo. La ruta más rápida es Expo, que incluye un bundler Metro preconfigurado, cliente de desarrollo y módulos nativos comunes.
npx create-expo-app@latest MyApp
cd MyApp
npx expo startEscanea el código QR con Expo Go en un dispositivo físico, o presiona i / a en la terminal para abrir el iOS Simulator o emulador de Android. Edita App.tsx - cada ejemplo de abajo puede reemplazar ese archivo para ejecutarse inmediatamente.
Herramientas: Estos ejemplos apuntan a Expo SDK 57, React Native 0.86 y React 19.2.3. TypeScript (
.tsx) se usa en todo; los proyectos de Expo lo incluyen por defecto.
Las dos primitivas con las que se construye cada pantalla de React Native - View para contenedores de layout y Text para todo lo que el usuario lee.
import { View, Text, StyleSheet } from "react-native";
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.title}>¡Hola, React Native!</Text>
<Text style={styles.subtitle}>Construido con View y Text.</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignItems: "center" },
title: { fontSize: 24, fontWeight: "bold" },
subtitle: { fontSize: 16, color: "#666", marginTop: 8 },
});<div> o <p> - View mapea a un contenedor nativo y Text mapea a un nodo de texto nativo<Text> - poner una cadena sin procesar dentro de View genera un error en tiempo de ejecuciónflex: 1 en el contenedor lo hace llenar toda la pantalla, que es el patrón de layout raíz estándarfontSize, no font-size)Relacionado: Views, Text & Core Components - reglas de anidamiento,
TextInputy peculiaridades del renderizado de plataforma
Usa StyleSheet.create para definir objetos de estilo reutilizables y validados en lugar de literales en línea.
import { View, Text, StyleSheet } from "react-native";
export default function App() {
return (
<View style={styles.card}>
<Text style={styles.heading}>StyleSheet.create</Text>
<Text style={styles.body}>
Los estilos se definen una vez y se hacen referencia por clave.
</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
margin: 16,
padding: 20,
backgroundColor: "#f0f4ff",
borderRadius: 12,
borderWidth: 1,
borderColor: "#c7d2fe",
},
heading: { fontSize: 18, fontWeight: "600", marginBottom: 8 },
body: { fontSize: 14, lineHeight: 20, color: "#374151" },
});StyleSheet.create valida nombres de propiedades en tiempo de desarrollo y envía una ID de estilo a la capa nativa en lugar de un objeto completo cada renderizadostyle={{ margin: 16 }}) funcionan para casos puntuales, pero StyleSheet es preferido para cualquier cosa reutilizada o compuestastyle={[styles.base, isActive && styles.active]} - las entradas posteriores anulan las anterioresem/remRelacionado: Views, Text & Core Components - cómo los estilos se adjuntan a vistas nativas
React Native usa Flexbox para todo el layout. El flexDirection por defecto es column, no row como muchos layouts web asumen.
import { View, Text, StyleSheet } from "react-native";
export default function App() {
return (
<View style={styles.screen}>
<View style={styles.header}>
<Text style={styles.headerText}>Encabezado</Text>
</View>
<View style={styles.row}>
<View style={[styles.box, styles.boxA]}>
<Text>A</Text>
</View>
<View style={[styles.box, styles.boxB]}>
<Text>B</Text>
</View>
</View>
<View style={styles.footer}>
<Text style={styles.footerText}>Pie de página</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, padding: 16 },
header: { padding: 12, backgroundColor: "#dbeafe", borderRadius: 8 },
headerText: { fontWeight: "600" },
row: { flex: 1, flexDirection: "row", gap: 12, marginVertical: 16 },
box: { flex: 1, justifyContent: "center", alignItems: "center", borderRadius: 8 },
boxA: { backgroundColor: "#bbf7d0" },
boxB: { backgroundColor: "#fde68a" },
footer: { padding: 12, backgroundColor: "#f3f4f6", borderRadius: 8 },
footerText: { textAlign: "center", color: "#6b7280" },
});flex: 1 en vistas hermanas las hace compartir el espacio restante equitativamente a lo largo del eje principal del padreflexDirection: "row" cambia el eje principal a horizontal - esencial para layouts lado a ladojustifyContent alinea hijos a lo largo del eje principal; alignItems alinea a lo largo del eje cruzadogap (RN 0.71+) añade espaciado entre hijos flex sin trucos de margenRelacionado: Dimensions & Responsive Layout - breakpoints, tablets y grillas adaptativas
Pressable es la primitiva táctil moderna - expone el estado de presión para que puedas estilizar retroalimentación sin un contenedor de opacidad separado.
import { useState } from "react";
import { View, Text, Pressable, StyleSheet } from "react-native";
export default function App() {
const [lastPress, setLastPress] = useState("No hay toques aún");
return (
<View style={styles.container}>
<Pressable
onPress={() => setLastPress(new Date().toLocaleTimeString())}
style={({ pressed }) => [
styles.button,
pressed && styles.buttonPressed,
]}
>
<Text style={styles.buttonText}>Tócame</Text>
</Pressable>
<Text style={styles.status}>{lastPress}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignItems: "center", gap: 16 },
button: {
backgroundColor: "#2563eb",
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
buttonPressed: { backgroundColor: "#1d4ed8", transform: [{ scale: 0.97 }] },
buttonText: { color: "#fff", fontWeight: "600", fontSize: 16 },
status: { color: "#6b7280" },
});style acepta una función ({ pressed }) => [...] para que el estilo de estado presionado se mantenga declarativoonPress se dispara en un toque completado; usa onPressIn / onPressOut para escenarios de presionar y mantener o arrastrarhitSlop para ampliar el objetivo táctil sin cambiar el tamaño visual - crítico para accesibilidad en iconos pequeñosPressable reemplaza a TouchableOpacity y TouchableHighlight en código nuevoRelacionado: Event Handling & Touchables -
hitSlop, presión prolongada y capas de gestos
useState funciona igual que en React para web - un cambio de estado programa un re-renderizado del árbol de componentes.
import { useState } from "react";
import { View, Text, Pressable, StyleSheet } from "react-native";
export default function App() {
const [count, setCount] = useState(0);
return (
<View style={styles.container}>
<Text style={styles.count}>{count}</Text>
<View style={styles.row}>
<Pressable style={styles.button} onPress={() => setCount((c) => c - 1)}>
<Text style={styles.buttonText}>−</Text>
</Pressable>
<Pressable style={styles.button} onPress={() => setCount((c) => c + 1)}>
<Text style={styles.buttonText}>+</Text>
</Pressable>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignItems: "center", gap: 24 },
count: { fontSize: 48, fontWeight: "bold" },
row: { flexDirection: "row", gap: 12 },
button: {
backgroundColor: "#2563eb",
width: 56,
height: 56,
borderRadius: 28,
justifyContent: "center",
alignItems: "center",
},
buttonText: { color: "#fff", fontSize: 24, fontWeight: "600" },
});count inmediatamente después de setCount aún devuelve el valor anteriorsetCount((c) => c + 1) cuando el nuevo valor depende del anterioruseState provoca un re-renderizado de este componente y sus hijos - mantén el estado lo más local posibleRelacionado: Props, State & Re-renders on Mobile - cómo las actualizaciones cruzan el límite JS/nativo
Muestra recursos agrupados locales con require() o imágenes remotas con un objeto fuente { uri }.
import { View, Image, Text, StyleSheet } from "react-native";
const REMOTE_URI =
"https://reactnative.dev/img/tiny_logo.png";
export default function App() {
return (
<View style={styles.container}>
<Image source={require("./assets/icon.png")} style={styles.local} />
<Image source={{ uri: REMOTE_URI }} style={styles.remote} />
<Text style={styles.caption}>Recurso local (arriba) y URI remoto (abajo)</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignItems: "center", gap: 16 },
local: { width: 64, height: 64, borderRadius: 12 },
remote: { width: 64, height: 64 },
caption: { fontSize: 13, color: "#6b7280", textAlign: "center", paddingHorizontal: 24 },
});require("./assets/icon.png") se resuelve en tiempo de construcción - el bundler incluye el archivo y elige la densidad correcta (@2x, @3x)width y height explícitos (o aspectRatio) - RN no puede inferir dimensiones de una URL solaresizeMode (cover, contain, stretch) para controlar cómo la imagen llena sus límitesexpo-image - cubierto en la guía de imágenes dedicadaRelacionado: Images & Assets - buckets de densidad,
expo-assety estrategias de caché
Envuelve el contenido de la pantalla en SafeAreaView para que aclare muescas, barras de estado e indicadores de inicio.
import { Text, StyleSheet } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function App() {
return (
<SafeAreaView style={styles.safe}>
<Text style={styles.title}>Layout de Área Segura</Text>
<Text style={styles.body}>
El contenido permanece debajo de la barra de estado y encima del indicador de inicio.
</Text>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safe: { flex: 1, padding: 20, backgroundColor: "#fff" },
title: { fontSize: 22, fontWeight: "bold", marginBottom: 8 },
body: { fontSize: 15, lineHeight: 22, color: "#4b5563" },
});react-native-safe-area-context, no desde react-native - el SafeAreaView incorporado es solo para iOS y está deprecado para nuevas appsreact-native-safe-area-context por defecto; envuelve tu raíz en SafeAreaProvider (la plantilla de Expo lo hace)useSafeAreaInsets() cuando necesites control por borde - p. ej., un encabezado desangrado con solo relleno superiorStatusBar desde expo-status-bar para hacer coincidir el estilo de la barra de estado con tu color de fondoRelacionado: Views, Text & Core Components - primitivas de layout a nivel de pantalla
Usa Platform.OS para branching simple y Platform.select para valores de estilo específicos de la plataforma.
import { View, Text, Platform, StyleSheet } from "react-native";
export default function App() {
return (
<View style={styles.container}>
<Text style={styles.label}>
Ejecutándose en {Platform.OS === "ios" ? "iOS" : "Android"}
</Text>
<View style={styles.card}>
<Text style={styles.cardText}>
{Platform.OS === "ios"
? "Fuente del sistema San Francisco"
: "Fuente del sistema Roboto"}
</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignItems: "center", gap: 16 },
label: { fontSize: 16, color: "#6b7280" },
card: {
padding: 20,
borderRadius: 12,
backgroundColor: "#f9fafb",
...Platform.select({
ios: {
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
android: { elevation: 4 },
}),
},
cardText: { fontSize: 15 },
});Platform.OS devuelve "ios", "android", "web" o "windows" - úsalo para ramas condicionales pequeñasPlatform.select({ ios: {...}, android: {...} }) devuelve el valor coincidente y se expande limpiamente en objetos StyleSheetshadow*; Android usa elevation - Platform.select es la forma idiomática de manejar esta división.ios.tsx / .android.tsx en lugar de condicionales en líneaRelacionado: Platform-Specific Code - extensiones de archivo, módulos nativos y
Platform.Version
Reacciona a cambios de tamaño de pantalla - rotación, plegables y tablets - con el hook useWindowDimensions.
import { View, Text, useWindowDimensions, StyleSheet } from "react-native";
export default function App() {
const { width } = useWindowDimensions();
const isTablet = width >= 768;
const columns = isTablet ? 3 : 2;
const gap = isTablet ? 16 : 8;
const horizontalPadding = 32;
const tileSize =
(width - horizontalPadding - gap * (columns - 1)) / columns;
return (
<View style={styles.container}>
<Text style={styles.heading}>
layout de {columns}-columnas ({Math.round(width)}px de ancho)
</Text>
<View style={[styles.grid, { gap }]}>
{Array.from({ length: 6 }, (_, i) => (
<View key={i} style={[styles.tile, { width: tileSize, height: tileSize }]}>
<Text>Elemento {i + 1}</Text>
</View>
))}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16 },
heading: { fontSize: 16, fontWeight: "600", marginBottom: 16 },
grid: { flexDirection: "row", flexWrap: "wrap" },
tile: {
backgroundColor: "#e0e7ff",
borderRadius: 8,
justifyContent: "center",
alignItems: "center",
},
});useWindowDimensions re-renderiza en rotación y cambio de tamaño de ventana, a diferencia del snapshot estático Dimensions.get("window")768 para tablet) como constantes nombradas compartidas en toda la appwidth menos padding y gaps - las dimensiones numéricas evitan sorpresas en layouts de porcentajeflexBasis y flexWrap en lugar de posicionamiento absolutoRelacionado: Dimensions & Responsive Layout - API
Dimensions, hooks de orientación y soporte plegable
Combina View, Text, Image, Pressable, StyleSheet y Platform.select en una tarjeta reutilizable e interactiva.
import { useState } from "react";
import {
View,
Text,
Image,
Pressable,
Platform,
StyleSheet,
} from "react-native";
const AVATAR_URI = "https://reactnative.dev/img/tiny_logo.png";
export default function App() {
const [following, setFollowing] = useState(false);
return (
<View style={styles.screen}>
<View style={styles.card}>
<Image source={{ uri: AVATAR_URI }} style={styles.avatar} />
<Text style={styles.name}>Alex Rivera</Text>
<Text style={styles.bio}>Desarrollador de React Native - 42 proyectos</Text>
<Pressable
onPress={() => setFollowing((f) => !f)}
style={({ pressed }) => [
styles.followButton,
following && styles.following,
pressed && styles.followPressed,
]}
>
<Text
style={[
styles.followText,
following && styles.followingText,
]}
>
{following ? "Siguiendo" : "Seguir"}
</Text>
</Pressable>
</View>
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, justifyContent: "center", padding: 24, backgroundColor: "#f3f4f6" },
card: {
backgroundColor: "#fff",
borderRadius: 16,
padding: 24,
alignItems: "center",
...Platform.select({
ios: {
shadowColor: "#000",
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.12,
shadowRadius: 8,
},
android: { elevation: 6 },
}),
},
avatar: { width: 80, height: 80, borderRadius: 40, marginBottom: 12 },
name: { fontSize: 20, fontWeight: "bold" },
bio: { fontSize: 14, color: "#6b7280", marginTop: 4, marginBottom: 16 },
followButton: {
backgroundColor: "#2563eb",
paddingHorizontal: 32,
paddingVertical: 10,
borderRadius: 20,
},
following: { backgroundColor: "#e5e7eb" },
followPressed: { opacity: 0.85 },
followText: { color: "#fff", fontWeight: "600" },
followingText: { color: "#374151" },
});View), contenido (Text, Image), interacción (Pressable) y estilo (StyleSheet)useState y deriva la etiqueta del botón y el estilo del mismo booleano - una única fuente de verdadname, bio, avatarUri) como el siguiente paso hacia una librería de componentesRelacionado: Props, State & Re-renders on Mobile - extrayendo componentes reutilizables | Best Practices - patrones para UI móvil lista para producción
Versiones de stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (
expo~57.0.4).
Revisado por Chris St. John·Última actualización: 16 jul 2026