CarlosSeijas
← Volver a los blogs

¿Qué es React Native? Guía completa del framework móvil

Código
React NativeReactDesarrollo MóvilJavaScriptAppsiOSAndroid
¿Qué es React Native? Guía completa del framework móvil

¿Te has preguntado alguna vez cómo apps como Instagram, Netflix o Uber logran funcionar tan bien en iOS y Android? La respuesta, en muchos casos, es React Native. Te voy a contar todo sobre este framework que revolucionó la forma de crear apps móviles, y por qué tantos developers (yo incluido) nos enamoramos de él.

React Native: el framework que cambió el juego móvil

React Native es un framework de código abierto que Facebook (ahora Meta) nos regaló al mundo en 2015. La idea es súper simple pero genial: usar JavaScript y React para crear aplicaciones móviles que se ven y se sienten completamente nativas.

Lo que me voló la mente cuando lo descubrí es que no estamos hablando de esas apps web empaquetadas que se sienten lentas y raras. React Native compila tu código JavaScript en componentes nativos reales de iOS y Android. Es como magia, pero con lógica.

Lo que hace especial a React Native:

La historia detrás del framework (y por qué me parece genial)

¿Por qué Facebook creó React Native?

En 2013, Facebook se enfrentaba a los mismos problemas que muchas empresas hoy:

  1. Desarrollo duplicado: Mantener equipos separados para iOS y Android era súper caro
  2. Inconsistencias: Era un dolor de cabeza mantener la misma experiencia en ambas plataformas
  3. Desarrollo lento: Los ciclos de desarrollo nativos tomaban forever
  4. Falta de talento: Había más developers web que developers móviles nativos

El timeline que cambió todo:

¿Por qué me encanta React Native?

1. Desarrollo súper eficiente

// Un solo código para ambas plataformas
const App = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>¡Hola Mundo!</Text>
      <Button title="Presionar" onPress={() => alert('Funciona!')} />
    </View>
  );
};

2. Rendimiento que no decepciona

3. Reutilización de código increíble

4. El ecosistema de React es tu amigo

5. Desarrollo que vuela

Las cosas no tan geniales (seamos honestos)

1. No es perfecto para todo

2. Dependes de terceros para muchas cosas

3. Las actualizaciones pueden ser intensas

4. Debugging: amor y odio

Te muestro código real (lo que más me gusta)

Ejemplo 1: Un formulario básico que funciona

import React, { useState } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';

const ContactForm = () => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = () => {
    console.log('Nombre:', name);
    console.log('Email:', email);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Contacto</Text>
      
      <TextInput
        style={styles.input}
        placeholder="Nombre"
        value={name}
        onChangeText={setName}
      />
      
      <TextInput
        style={styles.input}
        placeholder="Email"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
      />
      
      <Button title="Enviar" onPress={handleSubmit} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    padding: 20,
    backgroundColor: '#fff',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    marginBottom: 15,
    borderRadius: 5,
  },
});

export default ContactForm;

Ejemplo 2: Navegación entre pantallas (súper útil)

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { View, Text, Button } from 'react-native';

const Stack = createStackNavigator();

// Pantalla principal
const HomeScreen = ({ navigation }) => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ fontSize: 24, marginBottom: 20 }}>
        Pantalla Principal
      </Text>
      <Button
        title="Ir a Detalles"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
};

// Pantalla de detalles
const DetailsScreen = ({ navigation }) => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text style={{ fontSize: 24, marginBottom: 20 }}>
        Pantalla de Detalles
      </Text>
      <Button
        title="Volver"
        onPress={() => navigation.goBack()}
      />
    </View>
  );
};

// Configuración de navegación
const App = () => {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

export default App;

Ejemplo 3: Consumir APIs (lo de todos los días)

import React, { useState, useEffect } from 'react';
import { View, Text, FlatList, StyleSheet, ActivityIndicator } from 'react-native';

const UsersList = () => {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      const data = await response.json();
      setUsers(data);
    } catch (err) {
      setError('Error al cargar usuarios');
    } finally {
      setLoading(false);
    }
  };

  const renderUser = ({ item }) => (
    <View style={styles.userCard}>
      <Text style={styles.userName}>{item.name}</Text>
      <Text style={styles.userEmail}>{item.email}</Text>
      <Text style={styles.userCity}>{item.address.city}</Text>
    </View>
  );

  if (loading) {
    return (
      <View style={styles.centered}>
        <ActivityIndicator size="large" color="#0000ff" />
        <Text>Cargando usuarios...</Text>
      </View>
    );
  }

  if (error) {
    return (
      <View style={styles.centered}>
        <Text style={styles.error}>{error}</Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Lista de Usuarios</Text>
      <FlatList
        data={users}
        renderItem={renderUser}
        keyExtractor={(item) => item.id.toString()}
        showsVerticalScrollIndicator={false}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: '#f5f5f5',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
    textAlign: 'center',
  },
  userCard: {
    backgroundColor: '#fff',
    padding: 15,
    marginBottom: 10,
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  userName: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 5,
  },
  userEmail: {
    fontSize: 14,
    color: '#666',
    marginBottom: 3,
  },
  userCity: {
    fontSize: 14,
    color: '#888',
  },
  centered: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  error: {
    fontSize: 16,
    color: 'red',
    textAlign: 'center',
  },
});

export default UsersList;

Expo: la herramienta que me cambió la vida

¿Qué rayos es Expo?

Expo es básicamente React Native en modo fácil. Es una plataforma que eliminó todos los dolores de cabeza que tenía al principio con React Native. Sin configurar Xcode, sin Android Studio, sin problemas raros de builds.

Lo que hace Expo súper genial:

Por qué me enamoré de Expo

1. Es súper fácil empezar

# Crear proyecto con Expo
npx create-expo-app MyApp

# Iniciar desarrollo
cd MyApp
npx expo start

2. Testing que te vuela la mente

3. APIs que ya funcionan

// Ejemplo: Acceso a la cámara
import { Camera } from 'expo-camera';
import { useState, useEffect } from 'react';

const CameraExample = () => {
  const [hasPermission, setHasPermission] = useState(null);

  useEffect(() => {
    (async () => {
      const { status } = await Camera.requestCameraPermissionsAsync();
      setHasPermission(status === 'granted');
    })();
  }, []);

  if (hasPermission === null) {
    return <View />;
  }
  if (hasPermission === false) {
    return <Text>No access to camera</Text>;
  }

  return (
    <View style={{ flex: 1 }}>
      <Camera style={{ flex: 1 }} type={Camera.Constants.Type.back} />
    </View>
  );
};

4. Servicios que funcionan out-of-the-box

// Push notifications con Expo
import * as Notifications from 'expo-notifications';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

// Enviar notificación
await Notifications.scheduleNotificationAsync({
  content: {
    title: "¡Hola!",
    body: 'Notificación desde Expo',
  },
  trigger: { seconds: 2 },
});

5. Actualizaciones OTA (esto es magia)

// Actualizar app sin pasar por App Store
import * as Updates from 'expo-updates';

const checkForUpdates = async () => {
  try {
    const update = await Updates.checkForUpdateAsync();
    if (update.isAvailable) {
      await Updates.fetchUpdateAsync();
      Updates.reloadAsync();
    }
  } catch (e) {
    console.log(e);
  }
};

Lo no tan bueno de Expo (seamos justos)

1. Tienes limitaciones con librerías nativas

2. Las apps pueden ser más pesadas

3. Dependes de sus servicios

4. Rendimiento ligeramente inferior

Expo vs React Native CLI: la batalla épica

CaracterísticaExpoReact Native CLI
Configuración inicialMuy fácilCompleja
Testing en dispositivosInstantáneoCompilación requerida
APIs nativasLimitadas al SDKAcceso completo
Librerías tercerosLimitadasTodas disponibles
Tamaño appMás grandeOptimizado
Curva aprendizajeMuy bajaMedia-Alta
Control totalLimitadoCompleto

Mi consejo personal: cuándo usar cada uno

Usa Expo cuando:

Usa React Native CLI cuando:

Mi app de ejemplo con Expo (súper práctica)

// App.js - Aplicación completa con Expo
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, Button, Alert } from 'react-native';
import { StatusBar } from 'expo-status-bar';
import * as Location from 'expo-location';
import * as Notifications from 'expo-notifications';

export default function App() {
  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);

  useEffect(() => {
    (async () => {
      // Solicitar permisos de ubicación
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);

      // Configurar notificaciones
      await Notifications.requestPermissionsAsync();
    })();
  }, []);

  const sendNotification = async () => {
    await Notifications.scheduleNotificationAsync({
      content: {
        title: 'Ubicación actualizada',
        body: `Lat: ${location?.coords.latitude}, Lon: ${location?.coords.longitude}`,
      },
      trigger: { seconds: 1 },
    });
  };

  let text = 'Esperando ubicación...';
  if (errorMsg) {
    text = errorMsg;
  } else if (location) {
    text = `Lat: ${location.coords.latitude}, Lon: ${location.coords.longitude}`;
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Mi App con Expo</Text>
      <Text style={styles.location}>{text}</Text>
      
      {location && (
        <Button 
          title="Enviar Notificación" 
          onPress={sendNotification}
        />
      )}
      
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },
  location: {
    fontSize: 16,
    textAlign: 'center',
    marginBottom: 20,
  },
});

Los servicios de Expo que más uso

1. Expo Application Services (EAS) - game changer

# Build en la nube
eas build --platform ios
eas build --platform android

# Distribución
eas submit --platform ios
eas submit --platform android

2. Expo Updates - magia pura

3. Expo Notifications - súper fácil

4. Expo Analytics - datos útiles

Migración: cambiar de estrategia mid-project

De React Native CLI a Expo:

# Instalar SDK de Expo
npm install @expo/cli

# Configurar proyecto
npx expo install

De Expo a React Native CLI (el famoso Ejecting):

# Expo eject (versiones anteriores)
expo eject

# Alternativa moderna: Prebuild
npx expo prebuild

Mi conclusión sobre Expo

Expo es perfecto para:

Para proyectos más avanzados que necesitan control total, librerías nativas específicas o máximo rendimiento, React Native CLI sigue siendo la mejor opción.

Lo genial es que puedes empezar con Expo y migrar a React Native CLI cuando tu proyecto lo requiera. Lo mejor de ambos mundos.

La competencia (y por qué React Native sigue siendo mi favorito)

1. Flutter (Google) - el rival serio

// Ejemplo en Flutter
class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter App')),
        body: Center(child: Text('¡Hola Mundo!')),
      ),
    );
  }
}

Lo bueno de Flutter:

Lo que no me convence:

2. Xamarin (Microsoft) - el veterano

// Ejemplo en Xamarin
public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        Content = new StackLayout
        {
            Children = {
                new Label { Text = "¡Hola Mundo!" }
            }
        };
    }
}

Ventajas de Xamarin:

Desventajas:

3. Ionic - el híbrido

// Ejemplo en Ionic
import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  template: `
    <ion-content>
      <ion-button (click)="showAlert()">
        Mostrar Alerta
      </ion-button>
    </ion-content>
  `
})
export class HomePage {
  showAlert() {
    alert('¡Hola desde Ionic!');
  }
}

Lo bueno de Ionic:

Lo malo:

4. Desarrollo Nativo (Swift/Kotlin) - el gold standard

// iOS con Swift
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let label = UILabel()
        label.text = "¡Hola Mundo!"
        label.center = view.center
        view.addSubview(label)
    }
}
// Android con Kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        val textView = findViewById<TextView>(R.id.textView)
        textView.text = "¡Hola Mundo!"
    }
}

La batalla de frameworks: mi comparación honesta

CaracterísticaReact NativeFlutterXamarinIonicNativo
RendimientoMuy buenoExcelenteExcelenteBuenoExcelente
DesarrolloRápidoMedioMedioMuy rápidoLento
Curva aprendizajeBajaMediaMediaBajaAlta
EcosistemaMaduroCrecienteEstablecidoLimitadoNativo
Adopción empresarialAltaMediaMediaBajaAlta
Costo desarrolloBajoMedioAltoBajoAlto

Cuándo sí y cuándo NO usar React Native

React Native es perfecto para:

Mejor evítalo para:

Apps famosas que usan React Native (y me impresionan)

Facebook/Meta (obvio)

Otras empresas que me sorprenden

Cómo funciona por dentro (la parte técnica cool)

El Bridge JavaScript-Nativo

// JavaScript Thread
const nativeModule = NativeModules.MyCustomModule;
nativeModule.processData(data)
  .then(result => {
    // Resultado procesado nativamente
    console.log(result);
  });

Nueva Arquitectura con JSI (el futuro)

// Con JSI - comunicación directa
const result = global.nativeFunction(data);
// Sin bridge, ejecución síncrona

Empezar con React Native (los pasos que realmente importan)

Lo que necesitas instalar:

# Verificar Node.js y npm
node --version
npm --version

# Instalar React Native CLI
npm install -g react-native-cli

# Crear nuevo proyecto
npx react-native init MyApp

# Ejecutar en iOS
npx react-native run-ios

# Ejecutar en Android
npx react-native run-android

Así se ve un proyecto típico:

MyApp/ ├── android/ # Código Android nativo ├── ios/ # Código iOS nativo ├── src/ # Código JavaScript │ ├── components/ # Componentes React │ ├── screens/ # Pantallas │ └── services/ # Servicios API ├── package.json # Dependencias └── index.js # Punto de entrada

Las herramientas que uso todos los días

Herramientas esenciales:

Librerías que no pueden faltar:

// Navegación
import { NavigationContainer } from '@react-navigation/native';

// Gestión de estado
import { Provider } from 'react-redux';

// Networking
import axios from 'axios';

// Animaciones
import Animated from 'react-native-reanimated';

// Iconos
import Icon from 'react-native-vector-icons/FontAwesome';

El futuro que me emociona

Lo que viene:

Mi predicción para 2024-2025:

Mi conclusión después de años usando React Native

React Native se ha vuelto una solución súper sólida para desarrollo móvil multiplataforma. En mi experiencia, sus principales fortalezas son:

Las razones por las que lo sigo eligiendo:

Lo que debes considerar:

React Native es perfecto para equipos que ya saben React y buscan desarrollar apps móviles de calidad sin romper el presupuesto. Que empresas como Facebook, Netflix y Uber lo usen demuestra que sí funciona para proyectos grandes.

La nueva arquitectura que viene promete resolver muchas limitaciones actuales, así que React Native va a seguir siendo una opción súper atractiva.

Mi recomendación personal:

Si tu equipo maneja React y JavaScript, React Native ofrece una relación costo-beneficio increíble para la mayoría de proyectos móviles, especialmente cuando necesitas desarrollar rápido y el presupuesto está ajustado.

¿Ya has probado React Native? ¿Qué ha sido lo que más te ha gustado o lo que más te ha costado? Me encantaría saber tu experiencia.

Comentarios

Posts relacionados