Context y Provider para estado global de hábitos
Clase 15 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
Crear un estado global de hábitos confiable en React es más sencillo si organizas bien el context, el provider y las actualizaciones con useReducer y useEffect. Aquí verás cómo hidratar el estado desde AsyncStorage, cómo persistir cambios sin errores y cómo preparar las acciones de agregar y seleccionar hábitos. Todo, paso a paso, con buenas prácticas y mensajes de control en consola.
¿Cómo definir el context y el provider en React?
Para centralizar la lógica, se define un tipo que agrupe hábitos, estado de carga y funcionalidades. Luego, se crea el context con ese tipo y un valor por defecto nulo si no está disponible. El provider expone el estado y las funciones, devolviendo un ReactNode.
- Define un tipo con hábitos, loading y funciones de negocio.
- Crea el context con createContext y usa el tipo o null como valor inicial.
- Implementa el provider que retornará el Provider del contexto.
- Integra useReducer con un reducer y un initialState.
// Esquema orientativo
import React, { createContext, useReducer, useEffect } from 'react';
type HabitsContextType = {
habits: any[];
loading: boolean;
addHabit: (...args: any[]) => void;
selectHabit: (...args: any[]) => void;
};
const HabitsContext = createContext<HabitsContextType | null>(null);
function HabitsProvider({ children }: { children: React.ReactNode }) {
const [state, dispatch] = useReducer(reducer, initialState);
// acciones se implementan más abajo en el flujo
const addHabit = (...args: any[]) => dispatch({ type: 'add', payload: args });
const selectHabit = (...args: any[]) => dispatch({ type: 'select', payload: args });
return (
<HabitsContext.Provider value={{ habits: state.habits, loading: state.loading, addHabit, selectHabit }}>
{children}
</HabitsContext.Provider>
);
}
Clave: el useReducer retorna el estado y una función de actualización (dispatch), que permite ejecutar acciones con su payload.
¿Cómo hidratar el estado con AsyncStorage y useEffect?
La hidratación carga los hábitos guardados en la “memoria de la aplicación” con AsyncStorage. Se usa useEffect asíncrono, con try/catch, para leer por la clave definida (por ejemplo, storageKey), parsear el JSON y despachar la acción de hidratar.
- Usa un useEffect inicial para leer del almacenamiento.
- Llama a getItem con la key definida: storageKey.
- Convierte el “raw” a objeto con JSON.parse.
- Despacha { type: 'hydrate', payload } con los datos.
- Maneja errores con console.warn: "No se pudo cargar hábitos".
useEffect(() => {
(async () => {
try {
const raw = await AsyncStorage.getItem(storageKey);
if (!raw) return; // sin datos, no se hidrata
const data = JSON.parse(raw);
dispatch({ type: 'hydrate', payload: data });
} catch (e) {
console.warn('No se pudo cargar hábitos');
// opcional: asegurar un estado válido si algo falla
dispatch({ type: 'hydrate', payload: [] });
}
})();
}, []);
Importante: si no existe el tipo o la data, se devuelve null o un estado vacío, evitando rupturas en la UI.
¿Cómo guardar cambios y sincronizar hábitos sin errores?
Cada vez que cambian los hábitos, se debe persistir el estado. Para evitar escrituras redundantes, se usa un temporizador de guardado (save timer) y se limpia con clearTimeout antes de programar un nuevo guardado. Además, si el estado está loading, se evita guardar.
- Omite el guardado si state.loading es true.
- Usa un temporizador para controlar escrituras.
- Limpia con clearTimeout antes de programar otra operación.
- Guarda con AsyncStorage.setItem y JSON.stringify del estado.
- Controla errores: console.warn("No se pudo guardar").
- Devuelve una limpieza que cancele el temporizador activo.
const saveTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
if (state.loading) return; // no guardar mientras hidrata
if (saveTimer.current) clearTimeout(saveTimer.current);
saveTimer.current = setTimeout(async () => {
try {
await AsyncStorage.setItem(storageKey, JSON.stringify(state.habits));
} catch (e) {
console.warn('No se pudo guardar');
}
});
return () => {
if (saveTimer.current) clearTimeout(saveTimer.current);
};
}, [state.habits, state.loading]);
¿Qué acciones del reducer se exponen en el provider?
Al final, el provider expone las funciones conectadas al dispatch para operar sobre el estado global.
- Acción "hydrate": repuebla el estado con los hábitos cargados.
- Acción "add": agrega un hábito al listado.
- Acción "select": marca o selecciona un hábito.
Resultado: el context actúa como “centro de mando”, entregando estado y funcionalidades listas para usar en la aplicación.
¿Te gustaría ver cómo implementar y consumir este provider en tus componentes? Comparte tus dudas o casos y seguimos construyendo juntos.