Concepto clave
En el desarrollo de aplicaciones móviles con React Native, dos pilares fundamentales son la navegación y la gestión de estado. Imagina que tu aplicación es una ciudad: la navegación son las calles que conectan diferentes barrios (pantallas), mientras que el estado es la memoria colectiva de la ciudad que recuerda qué está pasando en cada lugar.
Para aplicaciones de lista de tareas, necesitas que los usuarios puedan moverse entre pantallas (como la lista principal y la pantalla de detalles) mientras mantienes un registro consistente de qué tareas existen, cuáles están completadas y cuáles pendientes. Esto requiere una arquitectura donde el estado sea accesible desde cualquier pantalla sin pasar datos manualmente entre componentes.
Cómo funciona en la práctica
Vamos a construir una aplicación de tareas con tres pantallas principales: una pantalla de lista, una pantalla de detalles y una pantalla para agregar nuevas tareas. Usaremos React Navigation para manejar la navegación entre ellas y Context API junto con useReducer para gestionar el estado global de las tareas.
Paso 1: Configuraremos un stack navigator con tres pantallas. Paso 2: Crearemos un contexto que almacene el estado de las tareas y funciones para agregar, eliminar y marcar como completadas. Paso 3: Conectaremos cada pantalla al contexto para leer y modificar el estado. El flujo será: el usuario ve la lista, toca una tarea para ver detalles, y desde allí puede marcarla como completada o eliminarla.
Codigo en accion
Primero, veamos cómo configurar el contexto del estado:
// TaskContext.js
import React, { createContext, useReducer, useContext } from 'react';
const TaskContext = createContext();
const initialState = {
tasks: [
{ id: '1', title: 'Aprender React Native', completed: false },
{ id: '2', title: 'Configurar Expo', completed: true }
]
};
function taskReducer(state, action) {
switch (action.type) {
case 'ADD_TASK':
return { ...state, tasks: [...state.tasks, action.payload] };
case 'TOGGLE_TASK':
return {
...state,
tasks: state.tasks.map(task =>
task.id === action.payload ? { ...task, completed: !task.completed } : task
)
};
case 'DELETE_TASK':
return {
...state,
tasks: state.tasks.filter(task => task.id !== action.payload)
};
default:
return state;
}
}
export function TaskProvider({ children }) {
const [state, dispatch] = useReducer(taskReducer, initialState);
return (
{children}
);
}
export function useTasks() {
return useContext(TaskContext);
}Ahora, aquí está cómo integrar la navegación con este estado en una pantalla de lista:
// TaskListScreen.js
import React from 'react';
import { View, FlatList, TouchableOpacity, Text } from 'react-native';
import { useTasks } from './TaskContext';
function TaskListScreen({ navigation }) {
const { state, dispatch } = useTasks();
const renderItem = ({ item }) => (
navigation.navigate('TaskDetail', { taskId: item.id })}
>
{item.title} - {item.completed ? 'Completada' : 'Pendiente'}
);
return (
item.id}
/>
navigation.navigate('AddTask')}>
Agregar Nueva Tarea
);
}
export default TaskListScreen;Errores comunes
- No envolver la app con el proveedor de contexto: Si olvidas envolver tu componente principal con TaskProvider, el contexto no estará disponible en las pantallas. Solución: Asegúrate de que App.js incluya alrededor del Navigator.
- Mutación directa del estado: Modificar el array de tareas directamente (ej., state.tasks.push()) causa errores. Siempre usa dispatch con acciones inmutables, como se muestra en el reducer.
- Navegación sin parámetros necesarios: Al navegar a TaskDetail, si no pasas taskId, la pantalla no sabrá qué tarea mostrar. Verifica que los parámetros estén definidos en navigation.navigate().
- Olvidar manejar el estado de carga: En apps reales, el estado podría cargarse de forma asíncrona. Agrega un estado de loading en el contexto para evitar errores en pantallas vacías.
Checklist de dominio
- Configuré un stack navigator con al menos tres pantallas usando React Navigation.
- Implementé un contexto con useReducer para gestionar tareas (agregar, eliminar, toggle).
- Conecté todas las pantallas al contexto para leer y modificar el estado.
- Probé la navegación entre pantallas pasando parámetros cuando es necesario.
- Manejé errores comunes como mutación de estado y parámetros faltantes.
- Agregué funcionalidad para persistir tareas (ej., usando AsyncStorage) opcionalmente.
- Probé la app en ambos iOS y Android para verificar consistencia.
Crea una app de lista de tareas con navegación y estado global
Sigue estos pasos para construir una aplicación funcional de lista de tareas que integre navegación y gestión de estado:
- Configura el proyecto: Crea un nuevo proyecto Expo con
npx create-expo-app TaskAppe instala React Navigation y las dependencias necesarias (@react-navigation/native,@react-navigation/stack). - Implementa el contexto de estado: Crea un archivo TaskContext.js similar al ejemplo, con un reducer que maneje ADD_TASK, TOGGLE_TASK y DELETE_TASK. Usa un estado inicial con al menos dos tareas de ejemplo.
- Configura la navegación: En App.js, configura un Stack Navigator con tres pantallas: TaskListScreen, TaskDetailScreen y AddTaskScreen. Envuelve el Navigator con TaskProvider.
- Desarrolla las pantallas:
- TaskListScreen: Muestra una lista de tareas usando FlatList, cada elemento debe navegar a TaskDetailScreen al tocar.
- TaskDetailScreen: Muestra los detalles de una tarea (título, estado) y botones para marcar como completada o eliminar, usando dispatch del contexto.
- AddTaskScreen: Incluye un formulario simple (TextInput y botón) para agregar nuevas tareas al contexto.
- Conecta el estado: En cada pantalla, usa el hook useTasks para acceder al estado y dispatch. Asegúrate de que los cambios se reflejen en todas las pantallas.
- Prueba la app: Ejecuta la app con
npx expo starty prueba en un emulador o dispositivo real. Verifica que la navegación funcione y el estado se mantenga consistente.
- Usa
useNavigationde React Navigation para acceder a la navegación en componentes que no son pantallas, si es necesario. - Para generar IDs únicos para tareas, considera usar
Date.now().toString()o una librería como uuid. - Si encuentras errores de rendimiento con FlatList, implementa
useMemoouseCallbackpara optimizar.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.