Lecciones aprendidas construyendo una app del clima con React
Desarrollar una aplicación del clima puede parecer simple a primera vista, pero la realidad es que presenta desafíos técnicos interesantes. Te comparto mi experiencia y las lecciones aprendidas al construir una app completa con React y TypeScript.
El proyecto
La aplicación del clima que desarrollé incluye:
-
Búsqueda de ciudades por nombre
-
Pronóstico del tiempo actual y extendido
-
Información detallada (humedad, viento, presión)
-
Interfaz responsive y accesible
-
Integración con múltiples APIs
-
Enlaces del proyecto:
- Website
-
API utilizada: OpenWeatherMap API
Puedes probar la aplicación directamente haciendo click en el enlace de arriba. La API de OpenWeatherMap es gratuita para uso básico y muy confiable para proyectos de desarrollo.
Desafíos técnicos encontrados
1. Integración de APIs
Uno de los mayores desafíos fue integrar múltiples APIs de manera eficiente:
interface WeatherAPI {
getCurrentWeather(city: string): Promise<WeatherData>;
getForecast(city: string): Promise<ForecastData>;
getGeocoding(city: string): Promise<GeocodingData>;
}
class OpenWeatherMapAPI implements WeatherAPI {
private apiKey: string;
private baseUrl = 'https://api.openweathermap.org/data/2.5';
constructor(apiKey: string) {
this.apiKey = apiKey;
}
async getCurrentWeather(city: string): Promise<WeatherData> {
const response = await fetch(
`${this.baseUrl}/weather?q=${city}&appid=${this.apiKey}&units=metric`
);
if (!response.ok) {
throw new Error(`Error: ${response.status}`);
}
return response.json();
}
}
2. Manejo de estados complejos
El estado de la aplicación se volvió complejo rápidamente:
interface WeatherState {
currentWeather: WeatherData | null;
forecast: ForecastData | null;
loading: boolean;
error: string | null;
searchHistory: string[];
favorites: string[];
}
const initialState: WeatherState = {
currentWeather: null,
forecast: null,
loading: false,
error: null,
searchHistory: [],
favorites: []
};
3. Optimización del rendimiento
Implementé varias técnicas para mejorar el rendimiento:
// Debounce para la búsqueda
const useDebounce = (value: string, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
// Memoización de componentes
const WeatherCard = React.memo(({ weather }: { weather: WeatherData }) => {
return (
<div className="weather-card">
<h3>{weather.city}</h3>
<p>{weather.temperature}°C</p>
</div>
);
});
Soluciones implementadas
1. Patrón de repositorio para APIs
Implementé un patrón de repositorio para manejar múltiples APIs:
class WeatherRepository {
private apis: WeatherAPI[];
constructor(apis: WeatherAPI[]) {
this.apis = apis;
}
async getWeatherData(city: string): Promise<WeatherData> {
for (const api of this.apis) {
try {
return await api.getCurrentWeather(city);
} catch (error) {
console.warn(`API ${api.constructor.name} failed:`, error);
continue;
}
}
throw new Error('All APIs failed');
}
}
2. Sistema de caché inteligente
Desarrollé un sistema de caché para evitar llamadas innecesarias:
class WeatherCache {
private cache = new Map<string, { data: any; timestamp: number }>();
private ttl = 5 * 60 * 1000; // 5 minutos
set(key: string, data: any): void {
this.cache.set(key, {
data,
timestamp: Date.now()
});
}
get(key: string): any | null {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return item.data;
}
}
3. Manejo de errores robusto
Implementé un sistema de manejo de errores que mejora la experiencia del usuario:
const useWeatherData = (city: string) => {
const [state, setState] = useState<WeatherState>(initialState);
const fetchWeather = async () => {
if (!city.trim()) return;
setState(prev => ({ ...prev, loading: true, error: null }));
try {
const [weather, forecast] = await Promise.all([
weatherAPI.getCurrentWeather(city),
weatherAPI.getForecast(city)
]);
setState(prev => ({
...prev,
currentWeather: weather,
forecast,
loading: false,
searchHistory: [...new Set([city, ...prev.searchHistory])].slice(0, 10)
}));
} catch (error) {
setState(prev => ({
...prev,
error: error instanceof Error ? error.message : 'Error desconocido',
loading: false
}));
}
};
return { ...state, fetchWeather };
};
Lecciones aprendidas
1. Planificación de la arquitectura es crucial
- Definir interfaces claras desde el inicio
- Separar responsabilidades entre componentes
- Pensar en la escalabilidad del código
2. El manejo de errores no es opcional
- Implementar fallbacks para cada posible fallo
- Proporcionar mensajes de error útiles al usuario
- Logging detallado para debugging
3. La optimización debe ser continua
- Medir el rendimiento constantemente
- Implementar lazy loading y code splitting
- Usar herramientas como React DevTools Profiler
4. La experiencia del usuario importa
- Estados de carga claros
- Feedback inmediato para las acciones
- Diseño responsive y accesible
Métricas de rendimiento
Los resultados finales fueron satisfactorios:
- Lighthouse Performance: 95/100
- First Contentful Paint: 1.2s
- Largest Contentful Paint: 2.1s
- Cumulative Layout Shift: 0.05
- First Input Delay: 45ms
Próximos pasos
Para futuras versiones, planeo implementar:
- PWA capabilities para uso offline
- Notificaciones push para alertas del clima
- Machine Learning para predicciones más precisas
- Integración con wearables para datos en tiempo real
Conclusión
Desarrollar esta aplicación del clima fue una experiencia invaluable que me enseñó mucho sobre:
- Arquitectura de aplicaciones React complejas
- Integración de APIs externas
- Optimización de rendimiento
- Manejo de estados y errores
- Experiencia del usuario
La clave del éxito fue la planificación cuidadosa y la implementación iterativa. Cada desafío superado me hizo un mejor desarrollador.
¿Has desarrollado alguna aplicación similar? ¿Qué desafíos encontraste? Me encantaría leer tu experiencia en los comentarios.
Recursos adicionales
Si te interesa desarrollar una aplicación similar, aquí tienes algunos recursos útiles:
- 📱 Demo en vivo: Prueba la aplicación funcionando
- 🔑 OpenWeatherMap API: Documentación oficial de la API
- 📚 React Documentation: Guía oficial de React
- 🎨 Tailwind CSS: Framework CSS utilizado en el proyecto
¿Te gustó este post? Sígueme en GitHub para más contenido técnico sobre desarrollo web.