Curso react nivel medio
Introducción
useReducer es un hook en React que proporciona una forma más avanzada de manejar el estado, ideal para aplicaciones complejas donde se necesitan múltiples actualizaciones de estado relacionadas o lógicas más estructuradas. Es similar a cómo funcionan los reducers en Redux.
¿Qué es useReducer?
useReducer gestiona el estado de un componente mediante un reducer, que es una función que recibe el estado actual y una acción, y devuelve un nuevo estado.
Sintaxis
1const [estado, dispatch] = useReducer(reducer, estadoInicial);
reducer: Una función que determina cómo cambia el estado según la acción.estadoInicial: El valor inicial del estado.dispatch: Una función para enviar acciones al reducer.
Ejemplo Básico: Contador
Código
1import React, { useReducer } from "react"; 2 3const estadoInicial = { contador: 0 }; 4 5function reducer(estado, accion) { 6 switch (accion.type) { 7 case "incrementar": 8 return { contador: estado.contador + 1 }; 9 case "decrementar": 10 return { contador: estado.contador - 1 }; 11 case "reiniciar": 12 return estadoInicial; 13 default: 14 throw new Error("Acción no reconocida"); 15 } 16} 17 18function Contador() { 19 const [estado, dispatch] = useReducer(reducer, estadoInicial); 20 21 return ( 22 <div> 23 <p>Contador: {estado.contador}</p> 24 <button onClick={() => dispatch({ type: "incrementar" })}> 25 Incrementar 26 </button> 27 <button onClick={() => dispatch({ type: "decrementar" })}> 28 Decrementar 29 </button> 30 <button onClick={() => dispatch({ type: "reiniciar" })}>Reiniciar</button> 31 </div> 32 ); 33} 34 35export default Contador;
Explicación
estadoInicial: Define el estado inicial del contador.reducer: Maneja las acciones (incrementar,decrementar,reiniciar) y devuelve el nuevo estado.dispatch: Envía una acción al reducer para actualizar el estado.
Ventajas de useReducer Sobre useState
- Estructura: Maneja estados complejos de manera más predecible.
- Escalabilidad: Ideal para lógica de estado complicada o relacionada.
- Agrupación de Actualizaciones: Permite combinar varias acciones en un solo reducer.
Ejemplo: Manejo de Formularios
useReducer puede ser útil para manejar formularios con múltiples campos y lógica de validación.
Código
1import React, { useReducer } from "react"; 2 3const estadoInicial = { 4 nombre: "", 5 correo: "", 6 errores: {}, 7}; 8 9function reducer(estado, accion) { 10 switch (accion.type) { 11 case "actualizar_campo": 12 return { 13 ...estado, 14 [accion.campo]: accion.valor, 15 }; 16 case "validar": 17 const errores = {}; 18 if (!estado.nombre) errores.nombre = "El nombre es obligatorio"; 19 if (!estado.correo.includes("@")) errores.correo = "Correo no válido"; 20 return { 21 ...estado, 22 errores, 23 }; 24 default: 25 throw new Error("Acción no reconocida"); 26 } 27} 28 29function Formulario() { 30 const [estado, dispatch] = useReducer(reducer, estadoInicial); 31 32 const manejarEnvio = (e) => { 33 e.preventDefault(); 34 dispatch({ type: "validar" }); 35 36 if (Object.keys(estado.errores).length === 0) { 37 alert("Formulario enviado correctamente"); 38 } 39 }; 40 41 return ( 42 <form onSubmit={manejarEnvio}> 43 <div> 44 <label> 45 Nombre: 46 <input 47 type="text" 48 value={estado.nombre} 49 onChange={(e) => 50 dispatch({ 51 type: "actualizar_campo", 52 campo: "nombre", 53 valor: e.target.value, 54 }) 55 } 56 /> 57 </label> 58 {estado.errores.nombre && <p style={{ color: "red" }}>{estado.errores.nombre}</p>} 59 </div> 60 <div> 61 <label> 62 Correo: 63 <input 64 type="email" 65 value={estado.correo} 66 onChange={(e) => 67 dispatch({ 68 type: "actualizar_campo", 69 campo: "correo", 70 valor: e.target.value, 71 }) 72 } 73 /> 74 </label> 75 {estado.errores.correo && <p style={{ color: "red" }}>{estado.errores.correo}</p>} 76 </div> 77 <button type="submit">Enviar</button> 78 </form> 79 ); 80} 81 82export default Formulario;
Explicación
estadoInicial: Contiene los valores iniciales del formulario.reducer:actualizar_campo: Actualiza el valor de un campo específico.validar: Realiza validaciones y actualiza los errores.
- Errores: Se muestran mensajes si no se cumplen las condiciones de validación.
Ejemplo: Lista de Tareas (To-Do List)
Código
1import React, { useReducer } from "react"; 2 3const estadoInicial = { tareas: [] }; 4 5function reducer(estado, accion) { 6 switch (accion.type) { 7 case "agregar_tarea": 8 return { 9 ...estado, 10 tareas: [...estado.tareas, { texto: accion.texto, completada: false }], 11 }; 12 case "eliminar_tarea": 13 return { 14 ...estado, 15 tareas: estado.tareas.filter((_, index) => index !== accion.index), 16 }; 17 case "toggle_tarea": 18 return { 19 ...estado, 20 tareas: estado.tareas.map((tarea, index) => 21 index === accion.index 22 ? { ...tarea, completada: !tarea.completada } 23 : tarea 24 ), 25 }; 26 default: 27 throw new Error("Acción no reconocida"); 28 } 29} 30 31function ListaTareas() { 32 const [estado, dispatch] = useReducer(reducer, estadoInicial); 33 const [texto, setTexto] = React.useState(""); 34 35 const manejarEnvio = (e) => { 36 e.preventDefault(); 37 if (texto.trim() === "") return; 38 dispatch({ type: "agregar_tarea", texto }); 39 setTexto(""); 40 }; 41 42 return ( 43 <div> 44 <h1>Lista de Tareas</h1> 45 <form onSubmit={manejarEnvio}> 46 <input 47 type="text" 48 value={texto} 49 onChange={(e) => setTexto(e.target.value)} 50 placeholder="Nueva tarea" 51 /> 52 <button type="submit">Agregar</button> 53 </form> 54 <ul> 55 {estado.tareas.map((tarea, index) => ( 56 <li key={index}> 57 <span 58 style={{ 59 textDecoration: tarea.completada ? "line-through" : "none", 60 }} 61 > 62 {tarea.texto} 63 </span> 64 <button onClick={() => dispatch({ type: "toggle_tarea", index })}> 65 {tarea.completada ? "Desmarcar" : "Completar"} 66 </button> 67 <button onClick={() => dispatch({ type: "eliminar_tarea", index })}> 68 Eliminar 69 </button> 70 </li> 71 ))} 72 </ul> 73 </div> 74 ); 75} 76 77export default ListaTareas;
Explicación
estadoInicial: Define una lista vacía de tareas.reducer:agregar_tarea: Añade una nueva tarea.eliminar_tarea: Elimina una tarea por su índice.toggle_tarea: Marca o desmarca una tarea como completada.
- Formulario: Agrega nuevas tareas con un campo de entrada.
¿Cuándo Usar useReducer?
-
Estados complejos:
- Cuando tienes múltiples estados relacionados que deben actualizarse juntos.
- Ejemplo: Formularios, listas dinámicas.
-
Acciones múltiples:
- Si un estado responde a varios tipos de acciones,
useReducerorganiza mejor el código.
- Si un estado responde a varios tipos de acciones,
-
Mejor legibilidad:
- Para aplicaciones grandes o complejas,
useReducerofrece una estructura más clara y mantenible.
- Para aplicaciones grandes o complejas,
Conclusión
useReducer es una alternativa poderosa a useState, especialmente en casos de lógica de estado compleja. Ayuda a estructurar y organizar tu lógica, haciendo que el código sea más predecible y escalable.