Objetivo del entorno de desarrollo
Para crear apps móviles con React Native necesitas un entorno que te permita: (1) ejecutar la app rápidamente (emulador/simulador), (2) probar en un dispositivo real, (3) depurar con herramientas confiables y (4) mantener una estructura de proyecto clara desde el primer día. En este capítulo usarás el flujo típico con React Native CLI (recomendado cuando quieres control nativo) y aprenderás los fundamentos de JSX y componentes para construir UI móvil.
Herramientas necesarias
Requisitos base
- Node.js (LTS) y un gestor de paquetes (
npmoyarn). - Git para control de versiones.
- Editor: VS Code (recomendado por ecosistema de extensiones).
- React Native CLI (se usa vía
npx, no necesitas instalar global).
Android (Windows/macOS/Linux)
- Android Studio (incluye SDK, Platform Tools y AVD Manager).
- Android SDK con una versión de API moderna (por ejemplo API 33+).
- Emulador configurado (AVD).
iOS (solo macOS)
- Xcode (incluye simuladores y herramientas de compilación).
- CocoaPods para dependencias nativas iOS (habitualmente requerido).
Extensiones útiles en VS Code
- ESLint y Prettier para estilo consistente.
- React Native Tools para ejecutar y depurar.
- TypeScript (si tu proyecto lo usa) para autocompletado y tipos.
Creación del proyecto y primera ejecución
Paso 1: crear un proyecto
Desde una carpeta de trabajo, crea el proyecto con React Native CLI:
npx react-native@latest init MiAppEntra al proyecto:
cd MiAppPaso 2: ejecutar en Android (emulador)
- Abre Android Studio > AVD Manager > crea/inicia un emulador.
- En otra terminal, ejecuta:
npx react-native run-androidEsto compila la app, instala el APK en el emulador y levanta el Metro Bundler (servidor de JavaScript) si no estaba corriendo.
Paso 3: ejecutar en iOS (simulador, macOS)
Instala pods (si aplica) y ejecuta:
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
cd ios && pod install && cd ..npx react-native run-iosSi tienes varios simuladores, puedes especificar uno:
npx react-native run-ios --simulator="iPhone 15"Paso 4: ejecutar en dispositivo real
Android (USB)
- Activa Opciones de desarrollador en el teléfono.
- Activa Depuración por USB.
- Conecta por USB y verifica que el dispositivo aparece:
adb devicesLuego ejecuta:
npx react-native run-androidAndroid (Wi‑Fi, opcional)
Si ya detecta el dispositivo por USB, puedes emparejar por red (según versión de platform-tools):
adb pair IP:PUERTOadb connect IP:PUERTODespués, el comando de ejecución es el mismo.
iOS (dispositivo real)
- En Xcode, abre
ios/MiApp.xcworkspace. - Selecciona tu dispositivo y configura el Team de firma.
- Ejecuta desde Xcode o con CLI (si está configurado):
npx react-native run-ios --deviceMetro, recarga y depuración
Metro Bundler
Metro es el servidor que empaqueta tu JavaScript y lo entrega a la app durante desarrollo. Si necesitas iniciarlo manualmente:
npx react-native startHot Reload / Fast Refresh
Fast Refresh aplica cambios de UI rápidamente sin recompilar todo el proyecto. Úsalo para iterar en pantallas y componentes.
Menú de desarrollador
Desde el emulador/simulador o dispositivo puedes abrir el menú de desarrollador para activar opciones como recarga, inspector y depuración. En Android suele ser con agitar el dispositivo o atajos del emulador; en iOS, también con agitar o desde el simulador.
Logs
Para ver logs del runtime:
npx react-native log-androidnpx react-native log-iosEstructura base de un proyecto React Native
Al crear el proyecto verás carpetas como android/ y ios/ (código nativo), y archivos como App.tsx o App.js (entrada de UI). Aunque puedes empezar editando App, conviene organizar desde el inicio una estructura escalable para pantallas, componentes y lógica.
Convención de carpetas inicial (recomendada)
Una propuesta simple y práctica:
src/ ├─ app/ │ ├─ AppRoot.tsx │ └─ providers/ ├─ screens/ │ ├─ HomeScreen.tsx │ └─ SettingsScreen.tsx ├─ components/ │ ├─ ui/ │ └─ layout/ ├─ navigation/ ├─ services/ ├─ hooks/ ├─ utils/ ├─ constants/ ├─ assets/ │ ├─ images/ │ └─ fonts/ └─ types/- screens/: pantallas completas (componen UI y orquestan datos).
- components/: piezas reutilizables (botones, cards, headers).
- services/: acceso a APIs, almacenamiento, lógica externa.
- hooks/: hooks personalizados (por ejemplo,
useDebounce). - utils/ y constants/: helpers y valores compartidos.
- types/: tipos y contratos (ideal si usas TypeScript).
En el archivo raíz App.tsx, puedes delegar a src/app/AppRoot.tsx para mantener el punto de entrada limpio.
Flujo de trabajo recomendado
Ciclo de desarrollo diario
- Inicia Metro:
npx react-native start(si no lo inicia el comando run). - Ejecuta en emulador/simulador:
npx react-native run-androidonpx react-native run-ios. - Desarrolla componentes y pantallas con Fast Refresh.
- Prueba en dispositivo real cuando uses cámara, sensores, rendimiento o comportamiento de teclado.
- Revisa logs y usa el inspector para estilos y jerarquía de componentes.
Errores comunes y cómo resolverlos
| Problema | Causa típica | Acción |
|---|---|---|
| La app abre en blanco | Metro caído o bundle no cargó | Reinicia Metro: npx react-native start --reset-cache |
| No detecta dispositivo Android | ADB/USB debugging | Verifica adb devices, cambia cable/puerto, acepta permisos |
| Build iOS falla por pods | Dependencias nativas | cd ios && pod install y recompila |
| Errores de Gradle | SDK/Java/Gradle mismatch | Revisa versiones en Android Studio y sincroniza |
Fundamentos de React Native: JSX y componentes
JSX en UI móvil
JSX es una sintaxis que te permite describir la UI usando etiquetas similares a HTML, pero en React Native renderizas componentes nativos como View, Text, Image, Pressable, etc. La idea es componer interfaces a partir de componentes pequeños.
Ejemplo de una tarjeta simple:
import React from 'react';import { View, Text, StyleSheet } from 'react-native';export function ProfileCard() { return ( <View style={styles.card}> <Text style={styles.title}>Hola, Ana</Text> <Text style={styles.subtitle}>React Native Developer</Text> </View> );}const styles = StyleSheet.create({ card: { padding: 16, borderRadius: 12, backgroundColor: '#fff' }, title: { fontSize: 18, fontWeight: '600' }, subtitle: { marginTop: 4, color: '#666' },});Componentes funcionales
Hoy lo más común es escribir componentes como funciones. Reciben props (entradas) y devuelven JSX (salida). Mantén los componentes pequeños: si un componente crece, extrae subcomponentes.
Props: entradas para reutilizar UI
Las props te permiten parametrizar un componente. Ejemplo de botón reutilizable:
import React from 'react';import { Pressable, Text, StyleSheet } from 'react-native';type PrimaryButtonProps = { label: string; onPress: () => void; disabled?: boolean;};export function PrimaryButton({ label, onPress, disabled }: PrimaryButtonProps) { return ( <Pressable onPress={onPress} disabled={disabled} style={({ pressed }) => [ styles.button, disabled && styles.buttonDisabled, pressed && !disabled && styles.buttonPressed, ]} > <Text style={styles.label}>{label}</Text> </Pressable> );}const styles = StyleSheet.create({ button: { backgroundColor: '#2563eb', paddingVertical: 12, paddingHorizontal: 16, borderRadius: 10, alignItems: 'center', }, buttonPressed: { opacity: 0.85 }, buttonDisabled: { backgroundColor: '#93c5fd' }, label: { color: '#fff', fontWeight: '600' },});Uso en una pantalla:
<PrimaryButton label="Guardar" onPress={() => console.log('Guardar')} />Estado local: UI que cambia con interacción
El estado local con useState sirve para representar datos que cambian en la pantalla: un contador, un texto de input, si un modal está abierto, si un botón está cargando, etc.
Ejemplo orientado a móvil: alternar “favorito” y reflejarlo en la UI:
import React, { useState } from 'react';import { View, Text, Pressable, StyleSheet } from 'react-native';export function FavoriteToggle() { const [isFavorite, setIsFavorite] = useState(false); return ( <View style={styles.row}> <Text style={styles.text}>Producto</Text> <Pressable onPress={() => setIsFavorite(v => !v)} style={[styles.pill, isFavorite ? styles.pillOn : styles.pillOff]} > <Text style={styles.pillText}>{isFavorite ? 'Favorito' : 'Marcar'}</Text> </Pressable> </View> );}const styles = StyleSheet.create({ row: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', padding: 16 }, text: { fontSize: 16 }, pill: { paddingVertical: 8, paddingHorizontal: 12, borderRadius: 999 }, pillOn: { backgroundColor: '#16a34a' }, pillOff: { backgroundColor: '#e5e7eb' }, pillText: { color: '#111827', fontWeight: '600' },});Renderizado condicional: mostrar/ocultar según estado
En apps móviles es común mostrar estados de carga, error o contenido. Puedes renderizar condicionalmente con operadores como ? o &&.
Ejemplo: botón con estado de carga:
import React, { useState } from 'react';import { View, Text, ActivityIndicator, StyleSheet } from 'react-native';import { PrimaryButton } from './PrimaryButton';export function SaveSection() { const [isSaving, setIsSaving] = useState(false); async function handleSave() { setIsSaving(true); try { await new Promise(r => setTimeout(r, 1200)); } finally { setIsSaving(false); } } return ( <View style={styles.container}> {isSaving ? ( <View style={styles.loadingRow}> <ActivityIndicator /> <Text style={styles.loadingText}>Guardando...</Text> </View> ) : ( <Text style={styles.hint}>Listo para guardar cambios</Text> )} <PrimaryButton label={isSaving ? 'Guardando' : 'Guardar'} onPress={handleSave} disabled={isSaving} /> </View> );}const styles = StyleSheet.create({ container: { padding: 16, gap: 12 }, hint: { color: '#6b7280' }, loadingRow: { flexDirection: 'row', alignItems: 'center', gap: 8 }, loadingText: { color: '#111827' },});Criterios para mantener el código legible desde el primer día
Reglas prácticas de organización
- Un componente por archivo (salvo componentes muy pequeños y privados).
- Nombres claros:
PrimaryButton,SettingsScreen,useAuth. - Evita estilos inline repetidos; usa
StyleSheet.createy extrae estilos compartidos. - Componentes UI vs. lógica: deja que
screens/orqueste datos y quecomponents/se enfoque en UI. - Props pequeñas: si un componente recibe demasiadas props, probablemente necesita dividirse o recibir un objeto (por ejemplo
user). - Estados explícitos: modela estados de UI como
isLoading,error,dataen lugar de múltiples banderas confusas. - Constantes y colores: centraliza en
src/constants/(por ejemplocolors.ts).
Ejemplo de constantes de diseño
// src/constants/colors.tsexport const colors = { primary: '#2563eb', text: '#111827', muted: '#6b7280', surface: '#ffffff', border: '#e5e7eb',};Uso en estilos:
import { StyleSheet } from 'react-native';import { colors } from '../constants/colors';export const styles = StyleSheet.create({ title: { color: colors.text, fontSize: 20, fontWeight: '700' },});Formato y calidad automática
Configura ESLint y Prettier para que el proyecto se mantenga consistente. Un patrón común es: Prettier para formato, ESLint para reglas. Asegúrate de ejecutar el formateo al guardar en el editor y agrega scripts en package.json:
{ "scripts": { "lint": "eslint .", "format": "prettier --write ." }}Checklist rápido antes de avanzar
- ¿Puedes ejecutar la app en emulador/simulador sin errores?
- ¿Puedes abrir el menú de desarrollador y ver logs?
- ¿Probaste al menos una vez en un dispositivo real?
- ¿Tu proyecto ya tiene
src/y una estructura mínima descreensycomponents? - ¿Tus componentes usan props y estado de forma clara y predecible?