Empezar tutorial interactivo

← Volver a Proyectos

Catálogo de Películas

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

📦 Dependencias de navegación

RN Movies Preview

Crea una aplicación móvil para explorar un catálogo de películas, ver detalles y navegar entre categorías, practicando navegación con React Navigation usando Bottom Tabs y Native Stack.

El proyecto usa datos locales (sin API) para enfocarse en la arquitectura de navegación, el tipado de parámetros y la composición de pantallas.

🌱 Cómo comenzar este proyecto

  1. Clona la siguiente plantilla en tu computadora
1https://github.com/breatheco-de/react-native-cli-hello
  1. Instala dependencias JS:
1npm install
  1. (Solo macOS/iOS) Instala CocoaPods:
1cd ios 2bundle install # opcional si usas Bundler 3bundle exec pod install || pod install 4cd ..
  1. Inicia Metro (servidor de desarrollo):
1npx react-native start --reset-cache
  1. Compila y ejecuta la app:
  • Android
    1npm run android
  • iOS (macOS)
    1npm run ios

📦 Dependencias de navegación

Instala React Navigation y dependencias nativas (si no están ya en package.json):

1npm install @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs 2npm install react-native-screens react-native-safe-area-context

En App.tsx envuelve tus navegadores con NavigationContainer:

1import { NavigationContainer } from '@react-navigation/native'; 2import TabsNavigator from './src/navigation/TabsNavigator'; 3 4export default function App() { 5 return ( 6 <NavigationContainer> 7 <TabsNavigator /> 8 </NavigationContainer> 9 ); 10}

🗂️ Estructura sugerida del proyecto

1├─ src/ 2│ ├─ navigation/ 3│ │ ├─ TabsNavigator.tsx # Tabs principales 4│ │ └─ StackNavigator.tsx # Stack para detalles y rutas internas 5│ ├─ screens/ 6│ │ ├─ HomeScreen.tsx # Lista de películas 7│ │ ├─ MovieDetailScreen.tsx # Detalle (recibe params tipados) 8│ │ ├─ CategoriesScreen.tsx # Lista de categorías 9│ │ └─ CategoryMoviesScreen.tsx # Películas filtradas por categoría 10│ ├─ components/ 11│ │ ├─ MovieCard.tsx 12│ │ └─ Grid.tsx 13│ ├─ data/ 14│ │ └─ movies.ts # Mock local (sin API) 15│ └─ types/ 16│ └─ index.ts # Tipos compartidos (Movie, Route params, etc.) 17├─ App.tsx 18├─ package.json 19└─ tsconfig.json

📝 Instrucciones

  1. Implementa Tabs + Stack con React Navigation:

    • Crea TabsNavigator.tsx para las pestañas Home, Categories y Favorites.
    • Dentro del tab Home, monta un Stack que navegue a MovieDetailScreen.
  2. Crea el archivo src/data/movies.ts con datos locales:

    1export type Movie = { 2 id: number; 3 title: string; 4 year: number; 5 categories: string[]; 6 rating: number; // 0–10 7}; 8 9export const movies: Movie[] = [ 10 { id: 1, title: 'Inception', year: 2010, categories: ['Sci-Fi', 'Action'], rating: 8.8 }, 11 { id: 2, title: 'Interstellar', year: 2014, categories: ['Sci-Fi', 'Drama'], rating: 8.6 }, 12 // ... 13];
  3. Usa rutas/params tipados en el Stack:

    • Define los tipos de navegación (por ejemplo RootStackParamList) en src/types/index.ts.
    • Al navegar al detalle, envía el id de la película y recupéralo en MovieDetailScreen.
  4. No uses fetch ni APIs externas: todo sale de movies.ts.

Esqueleto de navegadores (ejemplo)

src/navigation/StackNavigator.tsx

1import { createNativeStackNavigator } from '@react-navigation/native-stack'; 2import HomeScreen from '../screens/HomeScreen'; 3import MovieDetailScreen from '../screens/MovieDetailScreen'; 4import { RootStackParamList } from '../types'; 5 6const Stack = createNativeStackNavigator<RootStackParamList>(); 7 8export default function StackNavigator() { 9 return ( 10 <Stack.Navigator> 11 <Stack.Screen 12 name="Home" 13 component={HomeScreen} 14 options={{ title: 'Movies' }} 15 /> 16 <Stack.Screen 17 name="MovieDetail" 18 component={MovieDetailScreen} 19 options={({ route }) => ({ title: route.params?.title ?? 'Detail' })} 20 /> 21 </Stack.Navigator> 22 ); 23}

src/navigation/TabsNavigator.tsx

1import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; 2import StackNavigator from './StackNavigator'; 3import CategoriesScreen from '../screens/CategoriesScreen'; 4import FavoritesScreen from '../screens/FavoritesScreen'; 5 6type TabsParamList = { 7 Feed: undefined; // Contendrá el Stack (Home + Detail) 8 Categories: undefined; 9 Favorites: undefined; 10}; 11 12const Tab = createBottomTabNavigator<TabsParamList>(); 13 14export default function TabsNavigator() { 15 return ( 16 <Tab.Navigator> 17 <Tab.Screen 18 name="Feed" 19 component={StackNavigator} 20 options={{ title: 'Home' }} 21 /> 22 <Tab.Screen 23 name="Categories" 24 component={CategoriesScreen} 25 /> 26 <Tab.Screen 27 name="Favorites" 28 component={FavoritesScreen} 29 /> 30 </Tab.Navigator> 31 ); 32}

src/types/index.ts

1export type RootStackParamList = { 2 Home: undefined; 3 MovieDetail: { id: number; title?: string }; 4};

🖥️ Esqueleto de pantallas (ejemplo)

src/screens/HomeScreen.tsx

1import { View, FlatList, Pressable } from 'react-native'; 2import { NativeStackScreenProps } from '@react-navigation/native-stack'; 3import { RootStackParamList } from '../types'; 4import { movies } from '../data/movies'; 5import MovieCard from '../components/MovieCard'; 6 7type Props = NativeStackScreenProps<RootStackParamList, 'Home'>; 8 9export default function HomeScreen({ navigation }: Props) { 10 return ( 11 <View style={{ flex: 1, padding: 16 }}> 12 <FlatList 13 data={movies} 14 keyExtractor={(m) => String(m.id)} 15 renderItem={({ item }) => ( 16 <Pressable 17 onPress={() => 18 navigation.navigate('MovieDetail', { id: item.id, title: item.title }) 19 } 20 > 21 <MovieCard movie={item} /> 22 </Pressable> 23 )} 24 /> 25 </View> 26 ); 27}

src/screens/MovieDetailScreen.tsx

1import { View, Text } from 'react-native'; 2import { NativeStackScreenProps } from '@react-navigation/native-stack'; 3import { RootStackParamList } from '../types'; 4import { movies } from '../data/movies'; 5 6type Props = NativeStackScreenProps<RootStackParamList, 'MovieDetail'>; 7 8export default function MovieDetailScreen({ route }: Props) { 9 const { id } = route.params; 10 const movie = movies.find((m) => m.id === id); 11 12 if (!movie) return <Text style={{ padding: 16 }}>Movie not found</Text>; 13 14 return ( 15 <View style={{ flex: 1, padding: 16, gap: 6 }}> 16 <Text style={{ fontSize: 22, fontWeight: '600' }}>{movie.title}</Text> 17 <Text>Year: {movie.year}</Text> 18 <Text>Categories: {movie.categories.join(', ')}</Text> 19 <Text>Rating: {movie.rating}</Text> 20 </View> 21 ); 22}

💡 Tips

  • Los params suelen manejarse como tipos estrictos con NativeStackScreenProps y una ParamList.
  • Personaliza options del Stack para headers dinámicos (por ejemplo, usar el título de la película en el detalle).
  • Mantén componentes pequeños y reutilizables (MovieCard, Grid).
  • Si tus params llegan como string (por ej., desde inputs), conviértelos a number antes de buscar películas.

Regístrate para obtener acceso gratis a este proyecto

Lo usaremos para darte acceso a la comunidad.
¿Ya tienes una cuenta? Inicia sesión aquí.

Al registrarte estás aceptando nuestros Términos y condiciones y Política de privacidad.

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

Regístrate para obtener acceso gratis a este proyecto

Lo usaremos para darte acceso a la comunidad.
¿Ya tienes una cuenta? Inicia sesión aquí.

Al registrarte estás aceptando nuestros Términos y condiciones y Política de privacidad.

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías

Dificultad

  • intermediate

Duración promedio

2 hrs

Tecnologías