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:

  1. TodoApp (Componente Principal)

    • Maneja el estado global de las tareas.

    • Contiene el formulario para agregar nuevas tareas.

    • Renderiza la lista de tareas.

  2. 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:

EstadoTipoFunción
titlestringAlmacena el texto de la nueva tarea mientras se escribe en el input.
todosarrayGuarda la lista completa de tareas (cada una es un objeto con idtitlecompleted).
editItem (opcional)null o idControla 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:

    javascript
    Copy
    Download
    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:

    1. Prevenir el comportamiento por defecto del formulario (evitar recargar la página).

    2. Crear un nuevo objeto newTodo con los datos ingresados.

    3. 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:

    javascript
    Copy
    Download
    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.


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.


Resumen visual del flujo:

text
Copy
Download
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.

1. Agregar una Nueva Tarea

📌 Flujo:

  1. El usuario escribe en el <input> → dispara handleInputChange.

  2. Al enviar el formulario (onSubmit) → se ejecuta handleSubmit.

  3. Se crea un nuevo objeto newTodo con:

    • id: Un valor único (usamos Date.now()).

    • title: El texto ingresado (title).

    • completed: Inicia en false.

  4. Se actualiza todos con la nueva tarea.

📌 Código Clave:

jsx
Copy
Download
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:

  1. todos.map() recorre cada tarea y genera un componente <Todo> por cada una.

  2. Cada <Todo> recibe:

    • key={item.id} → Para optimización de React.

    • item={item} → Los datos de la tarea (texto, estado).

    • onUpdateonDelete → Funciones para modificar el estado global.

📌 Código Clave:

jsx
Copy
Download
<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 (onUpdateonDelete) como props.

📌 Todo → TodoApp (Hijo → Padre)

  • Ejecuta onUpdate(item.id, newTitle) o onDelete(item.id) para modificar todos.

📌 Ejemplo de Eliminación:

jsx
Copy
Download
// 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

text
Copy
Download
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

  • TodoApp maneja el estado global (todos).

  • Todo es un componente "tonto" (dumb component) que solo muestra datos y delega acciones al padre.

  • map() transforma el array todos en 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:

bash
Copy
Download
npx create-react-app todo-app
cd todo-app
mkdir src/components
touch src/components/TodoApp.js src/components/Todo.js src/components/todoApp.css

Paso 2: Componente principal (TodoApp.js)

jsx
Copy
Download
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)

jsx
Copy
Download
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 title mientras 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

  1. Agregar una tarea:

    • Escribe el texto en el input.

    • Presiona "Agregar" o Enter.

  2. Editar una tarea:

    • Haz clic en "Editar".

    • Modifica el texto en el input que aparece.

    • Presiona "Actualizar".

  3. Marcar como completado:

    • Usa el checkbox para cambiar el estado.

  4. Eliminar una tarea:

    • Haz clic en "Eliminar".

Paso 7: Mejoras posibles

  1. Persistencia de datos: Usar localStorage para guardar las tareas.

  2. Validación: No permitir tareas vacías.

  3. Filtros: Mostrar tareas completadas/incompletas.

  4. 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

Entradas más populares de este blog

0-Gestión de estado en una aplicación de tareas

2-Agregar una Tarea a tu Lista de Tareas en React