Ejercicio: Más hooks: useRef, useReducer y hooks propios
Objetivo
Construir una lista de la compra con useReducer para los cambios y useRef para manejar el foco.
Cómo se trabaja
Escribe un componente llamado App (puedes crear los demás que necesites). Prueba tu código en el editor de abajo; cuando funcione, pega todo el archivo en el comprobador. Los import de react se aceptan y se ignoran, porque aquí React ya está cargado.
Pasos
Marca cada paso a medida que lo completes. Tu avance se guarda en este navegador.
💡 Pista 1: el id
Para crear ids puedes usar Date.now() o un contador en una ref. Para el comprobador basta con que sean únicos.
💡 Pista 2: el foco
Crea const campo = useRef(null), pasa ref={campo} al <input> y llama campo.current.focus() después de despachar.
🔎 Comprueba tu trabajo
Pega tu código y pulsa Comprobar. La revisión ocurre en tu navegador; nada se envía a ningún sitio. Cada punto en rojo incluye una pista.
✅ Ver una solución posible
Intenta resolverlo antes de mirar. Tu versión puede ser distinta y también correcta.
import { useReducer, useRef, useState } from "react";
function reductor(lista, accion) {
switch (accion.tipo) {
case "agregar":
return [...lista, { id: accion.id, texto: accion.texto }];
case "quitar":
return lista.filter((p) => p.id !== accion.id);
default:
return lista;
}
}
export default function App() {
const [lista, dispatch] = useReducer(reductor, []);
const [texto, setTexto] = useState("");
const campo = useRef(null);
const siguienteId = useRef(1);
function agregar(e) {
e.preventDefault();
if (!texto.trim()) return;
dispatch({ tipo: "agregar", id: siguienteId.current++, texto: texto.trim() });
setTexto("");
campo.current.focus();
}
return (
<main>
<form onSubmit={agregar}>
<input name="producto" ref={campo} value={texto} onChange={(e) => setTexto(e.target.value)} />
<button type="submit">Agregar</button>
</form>
<ul>
{lista.map((p) => (
<li key={p.id}>
{p.texto} <button onClick={() => dispatch({ tipo: "quitar", id: p.id })}>Quitar</button>
</li>
))}
</ul>
</main>
);
}
💡 🏁 Reto extra (opcional)
Convierte la lógica de la lista en un hook personalizado useLista() que devuelva { lista, agregar, quitar }.