Implementación de un Gestor de Tareas con Redux Toolkit y React

Informática6,23 KB

1. Configuración del Estado Global: taskSlice.js

Definición del slice para gestionar las tareas mediante Redux Toolkit, incorporando generador de identificadores únicos con nanoid.

import { createSlice, nanoid } from '@reduxjs/toolkit';

const taskSlice = createSlice({
  name: 'tasks',
  initialState: [],
  reducers: {
    addTask: (state, action) => {
      // action.payload trae { nombre, descripcion }
      // AGREGA LA NUEVA TAREA AL ARREGLO DE ESTADO (Usando nanoid() para el id)
      state.push({
        id: nanoid(),
        nombre: action.payload.nombre,
        descripcion: action.payload.descripcion
      });
    },
    deleteTask: (state, action) => {
      // action.payload trae el id de la tarea a eliminar
      // REGRESA EL ESTADO SIN ESA TAREA
      return state.filter(task => task.id !== action.payload);
    },
    clearTasks: (state) => {
      // VACÍA POR COMPLETO LA LISTA DE TAREAS
      return [];
    },
  },
});

export const { addTask, deleteTask, clearTasks } = taskSlice.actions;
export default taskSlice.reducer;

2. Componentes de la Aplicación

Formulario de Tareas: TaskForm.jsx

Componente controlado para la captura y despacho de nuevas tareas hacia el store de Redux.

import { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addTask } from '../redux/taskSlice';

export default function TaskForm() {
  // DECLARA EL ESTADO LOCAL PARA NOMBRE Y DESCRIPCION
  const [nombre, setNombre] = useState('');
  const [descripcion, setDescripcion] = useState('');

  const dispatch = useDispatch();

  const handleSubmit = () => {
    // DISPARA addTask CON LOS DATOS DEL FORMULARIO Y LIMPIA LOS CAMPOS (Validando que no estén vacíos)
    if (nombre.trim() === '' || descripcion.trim() === '') {
      alert('Todos los campos son obligatorios');
      return;
    }
    
    dispatch(addTask({ nombre, descripcion }));
    setNombre('');
    setDescripcion('');
  };

  return (
    <div>
      {/* INPUTS CONTROLADOS CONECTADOS AL ESTADO LOCAL */}
      <input 
        type="text" 
        placeholder="Nombre de la tarea" 
        value={nombre} 
        onChange={(e) => setNombre(e.target.value)} 
      />
      <textarea 
        placeholder="Descripción de la tarea" 
        value={descripcion} 
        onChange={(e) => setDescripcion(e.target.value)} 
      />
      
      <button onClick={handleSubmit}>Agregar tarea</button>
    </div>
  );
}

Lista de Tareas: TaskList.jsx

Recupera la lista de tareas del estado global mediante el hook useSelector y mapea cada elemento.

import { useSelector } from 'react-redux';
import TaskItem from './TaskItem';

export default function TaskList() {
  // OBTÉN EL ARREGLO DE TAREAS DESDE EL STORE
  const tasks = useSelector(state => state.tasks);

  return (
    <div>
      {/* RECORRE LAS TAREAS Y RENDERIZA UN <TaskItem /> PASÁNDOLE LAS PROPS */}
      {tasks.map(task => (
        <TaskItem 
          key={task.id} 
          id={task.id} 
          nombre={task.nombre} 
          descripcion={task.descripcion} 
        />
      ))}
    </div>
  );
}

Elemento Individual: TaskItem.jsx

Presenta la información de una tarea puntual y expone la opción de eliminarla disparando la acción deleteTask.

import { useDispatch } from 'react-redux';
import { deleteTask } from '../redux/taskSlice';

// SE DECLARAN LAS PROPS QUE RECIBE EL COMPONENTE (id, nombre, descripcion)
export default function TaskItem({ id, nombre, descripcion }) {
  const dispatch = useDispatch();

  return (
    <div>
      {/* MUESTRA EL NOMBRE Y LA DESCRIPCIÓN RECIBIDOS POR PROPS */}
      <h3>{nombre}</h3>
      <p>{descripcion}</p>

      {/* DISPARA deleteTask USANDO EL ID RECIBIDO POR PROPS */}
      <button onClick={() => dispatch(deleteTask(id))}>
        Eliminar
      </button>
    </div>
  );
}

Página Principal: Page.jsx

Conecta la estructura principal al proveedor de contexto Provider y añade la acción global para vaciar el listado.

import { Provider } from 'react-redux';
import { store } from '../redux/store';
import TaskForm from '../components/TaskForm';
import TaskList from '../components/TaskList';
// IMPORTA clearTasks PARA EL BOTÓN DE "Eliminar todas"
import { clearTasks } from '../redux/taskSlice';

export default function Page() {
  return (
    <Provider store={store}>
      {/* ARMA LA PÁGINA USANDO TaskForm, TaskList Y UN BOTÓN QUE DISPARE clearTasks() */}
      <div>
        <TaskForm />
        <TaskList />
        <button onClick={() => store.dispatch(clearTasks())}>
          Eliminar todas
        </button>
      </div>
    </Provider>
  );
}

3. Respuestas de la Trivia para Puntos Extra

Para asegurar todos los puntos extra, aquí tienes las respuestas correctas de la trivia:

  • ¿Cuándo es el cumpleaños de Humberto? (Esta parece ser una broma interna de la clase, así que deja la respuesta que ya pusiste o la que sepas que el profesor espera).
  • ¿Nombre del primer Hokage? Hashirama Senju.
  • Menciona 3 integrantes de La Casa de los Famosos de la misma temporada: Wendy Guevara, Poncho de Nigris y Nicola Porcella (Temporada 1, México).
  • Da 4 vueltas corriendo...: ¡A hacer ejercicio físico!
  • ¿Cuántos océanos existen? (Nómbralos): Existen 5 océanos: Pacífico, Atlántico, Índico, Antártico (o Austral) y Ártico.
  • Menciona 6 Pokémon: Pikachu, Charizard, Bulbasaur, Squirtle, Gengar y Mewtwo.

Descargar

PDF Word HTML