1-Sistema de Tareas en React
Sistema de Tareas en React: Funcionamiento Completo
Vamos a desglosar cómo funciona el sistema completo para agregar y listar tareas en React, incluyendo los componentes necesarios, los estados y cómo interactúan entre sí.
📌 Componentes Necesarios
Nuestra aplicación se compone de:
TodoApp(Componente Principal)Maneja el estado global de las tareas.
Contiene el formulario para agregar nuevas tareas.
Renderiza la lista de tareas.
Todo(Componente Individual de Tarea)Muestra una tarea específica.
Permite editar, eliminar y marcar como completada.
⚡ Estados Clave y su Función
Los estados (useState) son fundamentales para manejar los datos dinámicos:
| Estado | Tipo | Función |
|---|---|---|
title | string | Almacena el texto de la nueva tarea mientras se escribe en el input. |
todos | array | Guarda la lista completa de tareas (cada una es un objeto con id, title, completed). |
editItem (opcional) | null o id | Controla qué tarea está en modo edición. |
🔧 Funcionamiento Paso a Paso
1. Usuario escribe en el <input> → dispara handleInputChange
¿Qué hace?
Esta función se ejecuta cada vez que el usuario escribe algo en el campo de texto (input). Su tarea principal es actualizar el estado del componente con el valor actual del input (por ejemplo, guardando lo que se escribe en una variable como title o inputValue).
¿Por qué es necesario?
Controlar el input: Sin handleInputChange, el input sería "no controlado" (uncontrolled), lo que significa que React no tendría conocimiento de su valor. Al sincronizar el valor del input con el estado del componente (usando value={state}), se hace "controlado" (controlled), permitiendo:
Validación en tiempo real.
Manipulación programática del valor (ej: resetearlo después de enviar el formulario).
Feedback inmediato: Si necesitas mostrar una vista previa o contar caracteres, necesitas guardar el valor en el estado.
Ejemplo de código:
const handleInputChange = (e) => {
setTitle(e.target.value); // Actualiza el estado "title" con lo que el usuario escribe.
};
¿Qué hace?
Esta función se ejecuta cada vez que el usuario escribe algo en el campo de texto (input). Su tarea principal es actualizar el estado del componente con el valor actual del input (por ejemplo, guardando lo que se escribe en una variable como title o inputValue).
¿Por qué es necesario?
Controlar el input: Sin
handleInputChange, el input sería "no controlado" (uncontrolled), lo que significa que React no tendría conocimiento de su valor. Al sincronizar el valor del input con el estado del componente (usandovalue={state}), se hace "controlado" (controlled), permitiendo:Validación en tiempo real.
Manipulación programática del valor (ej: resetearlo después de enviar el formulario).
Feedback inmediato: Si necesitas mostrar una vista previa o contar caracteres, necesitas guardar el valor en el estado.
Ejemplo de código:
const handleInputChange = (e) => { setTitle(e.target.value); // Actualiza el estado "title" con lo que el usuario escribe. };
2. Enviar formulario (onSubmit) → ejecuta handleSubmit
¿Qué hace?
Esta función se activa cuando el usuario envía el formulario (presionando Enter o un botón). Su objetivo es:
Prevenir el comportamiento por defecto del formulario (evitar recargar la página).
Crear un nuevo objeto newTodo con los datos ingresados.
Actualizar la lista de tareas (todos) agregando newTodo.
¿Por qué es necesario?
Gestionar el estado global: Aquí es donde la tarea se agrega formalmente a la lista (no durante el input).
Validación: Puedes verificar si el input está vacío antes de agregar la tarea.
Resetear el input: Tras agregar la tarea, se puede limpiar el campo (ej: setTitle("")).
Ejemplo de código:
const handleSubmit = (e) => {
e.preventDefault();
if (!title.trim()) return; // Validación
const newTodo = { id: Date.now(), title, completed: false };
setTodos([...todos, newTodo]); // Agrega la tarea
setTitle(""); // Limpia el input
};
¿Qué hace?
Esta función se activa cuando el usuario envía el formulario (presionando Enter o un botón). Su objetivo es:
Prevenir el comportamiento por defecto del formulario (evitar recargar la página).
Crear un nuevo objeto
newTodocon los datos ingresados.Actualizar la lista de tareas (
todos) agregandonewTodo.
¿Por qué es necesario?
Gestionar el estado global: Aquí es donde la tarea se agrega formalmente a la lista (no durante el
input).Validación: Puedes verificar si el input está vacío antes de agregar la tarea.
Resetear el input: Tras agregar la tarea, se puede limpiar el campo (ej:
setTitle("")).
Ejemplo de código:
const handleSubmit = (e) => { e.preventDefault(); if (!title.trim()) return; // Validación const newTodo = { id: Date.now(), title, completed: false }; setTodos([...todos, newTodo]); // Agrega la tarea setTitle(""); // Limpia el input };
3. Creación del objeto newTodo
id: Date.now()
Proporciona un identificador único (basado en la marca de tiempo) para distinguir cada tarea. Es clave para operaciones como borrar o editar tareas específicas.
title: texto ingresado
El contenido de la tarea que el usuario escribió en el input (guardado previamente en el estado por handleInputChange).
completed: false
Indica que la tarea está "no completada" por defecto. Es útil para implementar funcionalidades como marcar/desmarcar tareas.
id: Date.now()
Proporciona un identificador único (basado en la marca de tiempo) para distinguir cada tarea. Es clave para operaciones como borrar o editar tareas específicas.
title: texto ingresado
El contenido de la tarea que el usuario escribió en el input (guardado previamente en el estado por handleInputChange).
completed: false
Indica que la tarea está "no completada" por defecto. Es útil para implementar funcionalidades como marcar/desmarcar tareas.
4. Actualizar todos con la nueva tarea
¿Qué hace?
Toma el array existente de tareas (todos) y crea uno nuevo agregando newTodo (usando el spread operator [...todos, newTodo]).
¿Por qué es necesario?
En React, el estado es inmutable. No puedes modificar todos directamente (ej: todos.push(newTodo)). Debes crear un nuevo array para que React detecte el cambio y re-renderice el componente.
¿Qué hace?
Toma el array existente de tareas (todos) y crea uno nuevo agregando newTodo (usando el spread operator [...todos, newTodo]).
¿Por qué es necesario?
En React, el estado es inmutable. No puedes modificar todos directamente (ej: todos.push(newTodo)). Debes crear un nuevo array para que React detecte el cambio y re-renderice el componente.
Resumen visual del flujo:
Usuario escribe → handleInputChange (guarda el texto en el estado) → Envía formulario → handleSubmit (valida, crea newTodo, actualiza todos) → Limpia el input.
Conclusión: handleInputChange es esencial para rastrear el valor del input en tiempo real y mantenerlo sincronizado con el estado de React, lo que permite un control total sobre el formulario y su validación. Sin él, no podrías acceder al texto ingresado hasta que el formulario se enviara.
Usuario escribe → handleInputChange (guarda el texto en el estado) → Envía formulario → handleSubmit (valida, crea newTodo, actualiza todos) → Limpia el input.
handleInputChange es esencial para rastrear el valor del input en tiempo real y mantenerlo sincronizado con el estado de React, lo que permite un control total sobre el formulario y su validación. Sin él, no podrías acceder al texto ingresado hasta que el formulario se enviara.1. Agregar una Nueva Tarea
📌 Flujo:
El usuario escribe en el
<input>→ disparahandleInputChange.Al enviar el formulario (
onSubmit) → se ejecutahandleSubmit.Se crea un nuevo objeto
newTodocon:id: Un valor único (usamosDate.now()).title: El texto ingresado (title).completed: Inicia enfalse.
Se actualiza
todoscon la nueva tarea.
📌 Código Clave:
function handleSubmit(e) {
e.preventDefault();
const newTodo = {
id: Date.now(),
title: title,
completed: false,
};
setTodos([newTodo, ...todos]); // Agrega al principio
setTitle(""); // Limpia el input
}2. Renderizar la Lista de Tareas
📌 Flujo:
todos.map()recorre cada tarea y genera un componente<Todo>por cada una.Cada
<Todo>recibe:key={item.id}→ Para optimización de React.item={item}→ Los datos de la tarea (texto, estado).onUpdate,onDelete→ Funciones para modificar el estado global.
📌 Código Clave:
<div className="todosContainer">
{todos.map((item) => (
<Todo
key={item.id}
item={item}
onUpdate={handleUpdate}
onDelete={handleDelete}
/>
))}
</div>3. Comunicación Entre Componentes
📌 TodoApp → Todo (Padre → Hijo)
Pasa
item(datos) y funciones (onUpdate,onDelete) como props.
📌 Todo → TodoApp (Hijo → Padre)
Ejecuta
onUpdate(item.id, newTitle)oonDelete(item.id)para modificartodos.
📌 Ejemplo de Eliminación:
// En TodoApp:
function handleDelete(id) {
setTodos(todos.filter((todo) => todo.id !== id));
}
// En Todo.js:
<button onClick={() => onDelete(item.id)}>Eliminar</button>🎯 Diagrama de Flujo
1. User escribe → Actualiza `title` (Estado)
2. Envía formulario → `handleSubmit` → Actualiza `todos` (Estado)
3. React re-renderiza `TodoApp` → `todos.map()` genera lista
4. Cada `<Todo>` recibe sus props y maneja acciones
5. Si se edita/elimina → Llama a función en `TodoApp` → Actualiza `todos` → Ciclo se repite💡 Conclusión
TodoAppmaneja el estado global (todos).Todoes un componente "tonto" (dumb component) que solo muestra datos y delega acciones al padre.map()transforma el arraytodosen componentes React.keyúnica asegura que React renderice eficientemente.
En el próximo post veremos cómo implementar edición y eliminación en detalle. 🚀
Paso 1: Configuración inicial
Primero, crea un nuevo proyecto React y los archivos necesarios:
npx create-react-app todo-app
cd todo-app
mkdir src/components
touch src/components/TodoApp.js src/components/Todo.js src/components/todoApp.cssPaso 2: Componente principal (TodoApp.js)
import { useState } from "react";
import Todo from "./Todo";
import "./todoApp.css";
export default function TodoApp() {
// Estados para manejar el título, la lista de tareas y el ítem en edición
const [title, setTitle] = useState("");
const [todos, setTodos] = useState([]);
// Maneja el cambio en el input
function handleInputChange(e) {
setTitle(e.target.value);
}
// Maneja el envío del formulario para agregar nueva tarea
function handleSubmit(e) {
e.preventDefault();
const newTodo = {
id: Date.now(),
title: title,
completed: false,
};
// Agrega la nueva tarea al principio del array
const updatedTodos = [...todos];
updatedTodos.unshift(newTodo);
setTodos(updatedTodos);
setTitle(""); // Limpia el input después de agregar
}
// Elimina una tarea
function handleDelete(id) {
const filteredTodos = todos.filter((item) => item.id !== id);
setTodos([...filteredTodos]);
}
// Actualiza el texto de una tarea
function handleUpdate(id, value) {
const temp = [...todos];
const item = temp.find((item) => item.id === id);
item.title = value;
setTodos([...temp]);
}
// Maneja el cambio de estado (completado/no completado)
function handleCheckboxChange(id, status) {
const temp = [...todos];
const item = temp.find((item) => item.id === id);
item.completed = status;
setTodos([...temp]);
}
return (
<div className="todoContainer">
{/* Formulario para agregar nuevas tareas */}
<form onSubmit={handleSubmit} className="todoCreateForm">
<input
onChange={handleInputChange}
value={title}
className="todoInput"
placeholder="Ingresa una nueva tarea"
/>
<input
value="Agregar"
type={"submit"}
className="buttonCreate"
/>
</form>
{/* Lista de tareas */}
<div className="todosContainer">
{todos.map((item) => (
<Todo
key={item.id}
item={item}
onUpdate={handleUpdate}
onDelete={handleDelete}
onComplete={handleCheckboxChange}
/>
))}
</div>
</div>
);
}Paso 3: Componente Todo (Todo.js)
import { useState } from "react";
export default function Todo({ item, onUpdate, onDelete, onComplete }) {
// Estado para manejar el modo de edición
const [isEdit, setIsEdit] = useState(false);
// Estado para manejar el nuevo valor durante la edición
const [newValue, setNewValue] = useState(item.title);
// Componente para mostrar cuando estamos editando
function TodoEditForm() {
return (
<form className="todoEditForm" onSubmit={handleSubmit}>
<input
type="text"
className="todoInput"
value={newValue}
onChange={handleChange}
/>
<button className="button" onClick={handleSubmit}>
Actualizar
</button>
</form>
);
}
// Componente para mostrar cuando no estamos editando
function TodoElement() {
return (
<div className="todoInfo">
<span className={`todoTitle ${item.completed ? "completed" : ""}`}>
{item.title}
</span>
<div className="todoActions">
<input
type="checkbox"
checked={item.completed}
onChange={(e) => onComplete(item.id, e.target.checked)}
className="checkbox"
/>
<button onClick={() => setIsEdit(true)} className="button">
Editar
</button>
<button onClick={() => onDelete(item.id)} className="button delete">
Eliminar
</button>
</div>
</div>
);
}
// Maneja el cambio en el input de edición
function handleChange(e) {
setNewValue(e.target.value);
}
// Maneja el envío del formulario de edición
function handleSubmit(e) {
e.preventDefault();
onUpdate(item.id, newValue);
setIsEdit(false);
}
return (
<div className="todo">
{isEdit ? <TodoEditForm /> : <TodoElement />}
</div>
);
}
Explicación del código
1. Estados principales
title: Almacena el texto de la nueva tarea que se está escribiendo.
todos: Array que contiene todas las tareas, cada una con id, título y estado de completado.
2. Funciones principales
handleInputChange: Actualiza el estado
titlemientras el usuario escribe.handleSubmit: Crea una nueva tarea y la agrega al array
todos.handleDelete: Filtra el array para eliminar una tarea específica.
handleUpdate: Encuentra y actualiza el texto de una tarea específica.
handleCheckboxChange: Cambia el estado de completado de una tarea.
3. Componente Todo
Maneja su propio estado de edición (
isEdit) y el valor durante la edición (newValue).Muestra diferentes interfaces según si está en modo edición o no.
Proporciona botones para editar, eliminar y marcar como completado.
Paso 6: Uso de la aplicación
Agregar una tarea:
Escribe el texto en el input.
Presiona "Agregar" o Enter.
Editar una tarea:
Haz clic en "Editar".
Modifica el texto en el input que aparece.
Presiona "Actualizar".
Marcar como completado:
Usa el checkbox para cambiar el estado.
Eliminar una tarea:
Haz clic en "Eliminar".
Paso 7: Mejoras posibles
Persistencia de datos: Usar
localStoragepara guardar las tareas.Validación: No permitir tareas vacías.
Filtros: Mostrar tareas completadas/incompletas.
Ordenación: Permitir reorganizar tareas.
Este tutorial cubre los conceptos básicos de manejo de estado en React usando el hook useState, creación de componentes reutilizables y manejo de eventos.
Comentarios
Publicar un comentario