Cómo crear una ExploreCard específica para iOS y Android
Clase 18 de 23 • Curso de Fundamentos de React Native
Contenido del curso
- 5

Uso de constantes y condicionales en archivos TSX de React Native
10:36 - 6

Componentes reutilizables en React Native
14:50 - 7

StyleSheet y Flexbox en React Native
11:24 - 8

Paleta de colores con hooks en React Native
13:07 - 9

useState para interfaces dinámicas en React Native
12:12 - 10

Estado interactivo en React Native con useCallback
13:24 - 11

Pressable vs TouchableOpacity en React Native
09:37
- 12

Crear un carrusel con ScrollView horizontal
10:51 - 13

Diferencias entre ScrollView y FlatList para listas grandes
09:47 - 14

Instalación de Async Storage para persistencia de datos en React Native
14:54 - 15

Context y Provider para estado global de hábitos
12:08 - 16

AsyncStorage context para persistir hábitos
13:19 - 17

React Native: Provider de animación con confetti
11:58 - 18

Cómo crear una ExploreCard específica para iOS y Android
09:48 - 19

Implementación del tab Explore con FlatList y carga asíncrona
12:49 - 20

Contexto de perfil con persistencia y avatar aleatorio usando IA
12:32 - 21

Cámara y galería en React Native
16:01
Potencia tu vista de explore con un componente reusable y un servicio de sugerencias. Aquí verás cómo crear una ExploreCard accesible, aplicar estilos específicos para iOS y Android con Platform y construir un SuggestService que usa un catálogo por categoría con prioridades.
¿Cómo crear una ExploreCard con props y accesibilidad?
Para darle forma al tag de explore se construye un componente con props claras: emoji, título, subtítulo y acción. La acción se ejecuta al presionar, y se expone a través de las props para mantener la lógica desacoplada. También se añade accesibilidad con role y label del botón.
¿Qué props y type definen la interfaz?
- type con las props: emoji, title, subtitle, onPress.
- Acción disparada en onPress desde las props.
- Exportación del componente para reutilizarlo en el tag de explore.
// ExploreCard.tsx
import React from 'react';
import { View, Text, Pressable, Platform, StyleSheet } from 'react-native';
type ExploreCardProps = {
emoji: string;
title: string;
subtitle: string;
onPress: () => void;
};
export function ExploreCard({ emoji, title, subtitle, onPress }: ExploreCardProps) {
return (
<Pressable
onPress={onPress}
accessibilityRole="button"
accessibilityLabel={title}
style={[
styles.base,
Platform.OS === 'ios' ? styles.ios : styles.android,
styles.common,
]}
>
<View style={styles.emojiBox}>
<Text style={styles.emoji}>{emoji}</Text>
</View>
<View style={styles.textBox}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.subtitle}>{subtitle}</Text>
</View>
</Pressable>
);
}
const styles = StyleSheet.create({
base: { flexDirection: 'row', alignItems: 'center', padding: 16, borderRadius: 12 },
ios: { shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 8, shadowOffset: { width: 0, height: 4 } },
android: { elevation: 3 },
common: { backgroundColor: '#fff' },
emojiBox: { marginRight: 12 },
emoji: { fontSize: 24 },
textBox: { flex: 1 },
title: { fontSize: 16, fontWeight: '600' },
subtitle: { fontSize: 13, color: '#666' },
});
¿Cómo estructurar la vista con emoji, título y subtítulo?
- Contenedor para el emoji con tamaño visible.
- Bloque para textos: título claro y subtítulo descriptivo.
- Botón presionable que envuelve todo para capturar la acción.
¿Cómo aplicar estilos específicos por sistema operativo con Platform?
La clave está en combinar una base común con estilos condicionales por plataforma usando Platform. Así, la card se ve distinta en iOS y Android, sin duplicar estilos. Además, puedes sumar estilos comunes (p. ej., colores) al final del arreglo.
style:[
styles.base,
Platform.OS === 'ios' ? styles.ios : styles.android,
styles.common,
]
- Uso de Platform.OS para decidir entre iOS y Android.
- Base consistente para layout.
- Ajustes visuales nativos: sombras en iOS y elevation en Android.
¿Cómo construir un SuggestService con catálogo, modelo y fetch?
Se crea un servicio en TS para manejar sugerencias por categoría. Incluye un modelo que comparte campos con las cards y añade prioridad. Un catálogo agrupa hábitos por categorías como energía y enfoque, con id, emoji y prioridad. La selección puede simular una llamada a una API mediante fetch con POST, headers, body y try/catch; si no hay endpoint, se devuelve la sugerencia del catálogo según la categoría y prioridad.
¿Qué modelo y catálogo necesitas?
- Modelo con id, emoji, title, subtitle, priority.
- Catálogo indexado por categoría: energia, enfoque.
- Llaves de categoría tipadas para seguridad en TS.
// SuggestService.ts
export type HabitSuggestion = {
id: string;
emoji: string;
title: string;
subtitle: string;
priority: number;
};
type CategoryKey = 'energia' | 'enfoque';
const catalog: Record<CategoryKey, HabitSuggestion[]> = {
energia: [
{ id: 'energia_despertar', emoji: '☀️', title: 'Levantarte temprano', subtitle: 'Activa tu mañana', priority: 2 },
{ id: 'energia_hidratacion', emoji: '💧', title: 'Hidratación', subtitle: 'Más energía sostenida', priority: 1 },
],
enfoque: [
{ id: 'enfoque_bloques', emoji: '🎯', title: 'Trabajo en bloques', subtitle: 'Sin distracciones', priority: 1 },
{ id: 'enfoque_respiro', emoji: '🌬️', title: 'Pausa consciente', subtitle: 'Recupera foco', priority: 2 },
],
};
export async function getByCategory(key: CategoryKey): Promise<HabitSuggestion[]> {
await new Promise(r => setTimeout(r, 300));
return catalog[key];
}
¿Cómo simular la llamada a la API y manejar errores?
- Endpoint opcional para IA simulada.
- Envío de category, profileName y habits en el body.
- Manejo de latencia con await y control de errores con try/catch.
type SuggestParams = {
category: CategoryKey;
profileName: string;
habits: string[];
};
const ENDPOINT = '';
export async function suggestService(params: SuggestParams): Promise<HabitSuggestion> {
const { category } = params;
try {
if (ENDPOINT) {
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params),
});
if (!res.ok) throw new Error('Network error');
const data = await res.json();
return data.suggestion as HabitSuggestion;
}
// Fallback: usar catálogo local.
await new Promise(r => setTimeout(r, 400));
const list = catalog[category];
return list.sort((a, b) => a.priority - b.priority)[0];
} catch (error) {
// Repropagar para identificar el fallo aguas arriba.
throw error;
}
}
¿Tienes otra categoría o hábito que quisieras priorizar? Comenta tu caso y lo integramos en el catálogo.