Context y provider para persistir hábitos en React Native

Clase 16 de 23Curso de Fundamentos de React Native

Resumen

Mantén tus hábitos incluso al cerrar y reabrir la app: con persistencia de datos, un context centralizado y un provider bien configurado, toda la UI en home y tabs accede a la misma fuente de verdad. La información vive en asset storage y se expone mediante un hook reusable, evitando duplicaciones y errores.

¿Cómo implementar persistencia con context y provider?

Para que los hábitos no se pierdan, se almacena el estado en asset storage y se entrega mediante un provider. Se retorna un ReactNode envolviendo a los children y se expone un value con el estado y las acciones. Así, al salir y volver a abrir, los datos permanecen.

  • Estado compartido: loading, habits y acciones como add habit y toggle habit.
  • Provider: entrega value y recibe children.
  • Consistencia de nombres: usa el mismo nombre del context al crear y consumir.
import React, { createContext, useContext, useState, useMemo } from 'react'; const HabitsContext = createContext(null); export function HabitsProvider({ children }) { const [habits, setHabits] = useState([]); const [loading, setLoading] = useState(true); const [timer, setTimer] = useState<number>(250); // tipado de setTimer como number const addHabit = (id) => { // lógica para agregar hábito y persistir en asset storage }; const toggleHabit = (id, day) => { // lógica para alternar completado por día y persistir }; const value = useMemo(() => ({ loading, habits, addHabit, toggleHabit }), [loading, habits]); return ( <HabitsContext.Provider value={value}> {children} </HabitsContext.Provider> ); }

¿Qué hook reusable garantiza seguridad al consumir el context?

Se exporta un hook sin parámetros, con verificación estricta: si no existe context, se hace throw con un mensaje claro. Asegúrate de retornar el ctx completo para acceder a todo.

export function useHabits() { const ctx = useContext(HabitsContext); if (!ctx) throw new Error('useHabits debe usarse dentro de HabitsProvider'); return ctx; // retorna todo el contexto }

¿Cómo integrar el provider en la navegación y en home?

El provider debe envolver el árbol completo donde vive la UI (por ejemplo, las tabs), igual que se hace con el theme. Así, cualquier pantalla puede leer y actualizar hábitos desde el context.

export default function App() { return ( <HabitsProvider> <Tabs /> </HabitsProvider> ); }
  • Importa desde el context: trae loading, habits y add habit con useHabits.
  • Migra lógica local: reemplaza manejadores locales por funciones del context.
  • Render: usa habits en lugar de items y elimina el key extractor externo si ya hay llaves.

¿Cómo definir onAdd con useCallback y validar entrada?

La adición de hábitos sale de la pantalla y se delega al context. Se valida el título y se limpia el estado local después.

import { useCallback, useState } from 'react'; import { useHabits } from './habits-context'; function Home() { const { addHabit } = useHabits(); const [title, setTitle] = useState(''); const onAdd = useCallback(() => { const id = title; // identificador por título if (!title) return; // validación addHabit(id); setTitle(''); // limpiar estado local }, [title, addHabit]); // ... }

¿Cómo alternar el completado diario y mostrar loading?

Usa la función del context para alternar sin gestionar estado duplicado en home. Muestra un texto si loading es verdadero.

function Home() { const { loading, habits, toggleHabit } = useHabits(); const today = new Date(); const esMismoDia = (a, b) => a.toDateString() === b.toDateString(); if (loading) return <Text>Cargando…</Text>; const renderItem = ({ item }) => ( <HabitCard habit={item} onToggle={() => toggleHabit(item.id, today)} // alterna completado hoy /> ); return ( <FlatList data={habits} renderItem={renderItem} // sin key extractor externo si ya hay llaves /> ); }

¿Qué ajustes garantizan consistencia y limpieza del estado?

Con la lógica centralizada, se simplifica la UI y se evitan errores comunes.

  • Filtrado de completados por día: usa habits y verifica el día actual antes de contar rachas.
  • Nombres consistentes: asegúrate de usar el mismo nombre del context al crearlo y al consumirlo.
  • Retorno de contexto: en useHabits, retorna el ctx completo para exponer todo.
  • Botón de limpieza: agrega un botón que haga un “clear” del assing storage para reiniciar hábitos.
// Ejemplo de botón para limpiar almacenamiento <Button title="Limpiar" onPress={async () => { // hacer un clear del assing storage y recargar si es necesario }} />

Además, al recargar desde Expo Go verás que las tarjetas reaparecen según lo guardado; si limpias y recargas, vuelves a cero. Con estas bases ya puedes persistir hábitos, marcarlos como completados y mantener rachas sin perder datos.

¿Te gustaría conectar las sugerencias del Explorer para añadir directamente a la pantalla principal? Cuéntalo en comentarios y comparte qué más te gustaría automatizar.

      Context y provider para persistir hábitos en React Native