Introducción
Redux es una librería de JavaScript para la gestión del estado de aplicaciones. Es especialmente útil en aplicaciones grandes donde el manejo del estado puede volverse complejo y difícil de mantener. Redux se basa en tres principios fundamentales:
- Estado Único: Toda la información de la aplicación se almacena en un único objeto de estado.
- Estado de Solo Lectura: El estado es inmutable y solo puede ser modificado emitiendo acciones.
- Cambios mediante Funciones Puras: Los cambios en el estado se realizan mediante funciones puras llamadas reductores (reducers).
Instalación de Redux
Para comenzar a usar Redux en tu proyecto, primero necesitas instalarlo. Puedes hacerlo usando npm o yarn:
O con yarn:
Conceptos Básicos de Redux
Estado (State)
El estado en Redux es un objeto que contiene toda la información de la aplicación. Este estado es inmutable y solo puede ser modificado mediante acciones.
Acciones (Actions)
Las acciones son objetos que describen un cambio en el estado. Cada acción debe tener una propiedad type
que indica el tipo de acción a realizar. Opcionalmente, pueden incluir datos adicionales.
Reductores (Reducers)
Los reductores son funciones puras que toman el estado actual y una acción como argumentos, y devuelven un nuevo estado. No deben tener efectos secundarios ni modificar el estado directamente.
const initialState = { count: 0 }; function counterReducer(state = initialState, action) { switch (action.type) { case 'INCREMENT': return { count: state.count + action.payload }; case 'DECREMENT': return { count: state.count - action.payload }; default: return state; } }
Store
El store es el objeto que contiene el estado de la aplicación. Se crea usando el reductor y proporciona métodos para acceder al estado, despachar acciones y suscribirse a cambios en el estado.
Ejemplo Práctico
Vamos a crear una pequeña aplicación de contador usando Redux.
Paso 1: Definir Acciones
// actions.js export const increment = (value) => ({ type: 'INCREMENT', payload: value }); export const decrement = (value) => ({ type: 'DECREMENT', payload: value });
Paso 2: Crear el Reductor
// reducer.js const initialState = { count: 0 }; export function counterReducer(state = initialState, action) { switch (action.type) { case 'INCREMENT': return { count: state.count + action.payload }; case 'DECREMENT': return { count: state.count - action.payload }; default: return state; } }
Paso 3: Crear el Store
// store.js import { createStore } from 'redux'; import { counterReducer } from './reducer'; export const store = createStore(counterReducer);
Paso 4: Conectar React con Redux
Para conectar React con Redux, usamos el paquete react-redux
.
// App.js import React from 'react'; import { Provider, useDispatch, useSelector } from 'react-redux'; import { store } from './store'; import { increment, decrement } from './actions'; function Counter() { const count = useSelector((state) => state.count); const dispatch = useDispatch(); return ( <div> <h1>{count}</h1> <button onClick={() => dispatch(increment(1))}>Increment</button> <button onClick={() => dispatch(decrement(1))}>Decrement</button> </div> ); } function App() { return ( <Provider store={store}> <Counter /> </Provider> ); } export default App;
Ejercicio Práctico
Ejercicio
Crea una aplicación de lista de tareas (To-Do List) usando Redux. La aplicación debe permitir agregar, eliminar y marcar tareas como completadas.
Requisitos
- Acciones: Define acciones para agregar, eliminar y marcar tareas.
- Reductor: Crea un reductor que maneje las acciones definidas.
- Store: Configura el store con el reductor.
- Componentes: Crea componentes React para mostrar y manipular la lista de tareas.
- Conexión: Conecta los componentes React con Redux usando
react-redux
.
Solución
Acciones
// actions.js export const addTask = (task) => ({ type: 'ADD_TASK', payload: task }); export const removeTask = (id) => ({ type: 'REMOVE_TASK', payload: id }); export const toggleTask = (id) => ({ type: 'TOGGLE_TASK', payload: id });
Reductor
// reducer.js const initialState = { tasks: [] }; export function tasksReducer(state = initialState, action) { switch (action.type) { case 'ADD_TASK': return { tasks: [...state.tasks, { id: Date.now(), text: action.payload, completed: false }] }; case 'REMOVE_TASK': return { tasks: state.tasks.filter(task => task.id !== action.payload) }; case 'TOGGLE_TASK': return { tasks: state.tasks.map(task => task.id === action.payload ? { ...task, completed: !task.completed } : task ) }; default: return state; } }
Store
// store.js import { createStore } from 'redux'; import { tasksReducer } from './reducer'; export const store = createStore(tasksReducer);
Componentes
// App.js import React, { useState } from 'react'; import { Provider, useDispatch, useSelector } from 'react-redux'; import { store } from './store'; import { addTask, removeTask, toggleTask } from './actions'; function TaskList() { const tasks = useSelector((state) => state.tasks); const dispatch = useDispatch(); const [task, setTask] = useState(''); const handleAddTask = () => { if (task.trim()) { dispatch(addTask(task)); setTask(''); } }; return ( <div> <input type="text" value={task} onChange={(e) => setTask(e.target.value)} placeholder="Add a new task" /> <button onClick={handleAddTask}>Add Task</button> <ul> {tasks.map((task) => ( <li key={task.id}> <span style={{ textDecoration: task.completed ? 'line-through' : 'none' }} onClick={() => dispatch(toggleTask(task.id))} > {task.text} </span> <button onClick={() => dispatch(removeTask(task.id))}>Remove</button> </li> ))} </ul> </div> ); } function App() { return ( <Provider store={store}> <TaskList /> </Provider> ); } export default App;
Conclusión
En esta sección, hemos aprendido los conceptos básicos de Redux y cómo integrarlo con React para gestionar el estado de una aplicación. Hemos cubierto la creación de acciones, reductores y el store, así como la conexión de componentes React con Redux. Además, hemos implementado una aplicación de contador y una lista de tareas para practicar estos conceptos.
En el siguiente módulo, exploraremos más sobre los frameworks y librerías de JavaScript, comenzando con una introducción a React.
JavaScript: De Principiante a Avanzado
Módulo 1: Introducción a JavaScript
- ¿Qué es JavaScript?
- Configuración de tu Entorno de Desarrollo
- Tu Primer Programa en JavaScript
- Sintaxis y Conceptos Básicos de JavaScript
- Variables y Tipos de Datos
- Operadores Básicos
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for, while, do-while
- Sentencias Switch
- Manejo de Errores con try-catch
Módulo 3: Funciones
- Definición y Llamada de Funciones
- Expresiones de Función y Funciones Flecha
- Parámetros y Valores de Retorno
- Ámbito y Closures
- Funciones de Orden Superior
Módulo 4: Objetos y Arrays
- Introducción a los Objetos
- Métodos de Objeto y la Palabra Clave 'this'
- Arrays: Conceptos Básicos y Métodos
- Iteración sobre Arrays
- Desestructuración de Arrays
Módulo 5: Objetos y Funciones Avanzadas
- Prototipos y Herencia
- Clases y Programación Orientada a Objetos
- Módulos e Importación/Exportación
- JavaScript Asíncrono: Callbacks
- Promesas y Async/Await
Módulo 6: El Modelo de Objetos del Documento (DOM)
- Introducción al DOM
- Selección y Manipulación de Elementos del DOM
- Manejo de Eventos
- Creación y Eliminación de Elementos del DOM
- Manejo y Validación de Formularios
Módulo 7: APIs del Navegador y Temas Avanzados
- Almacenamiento Local y de Sesión
- Fetch API y AJAX
- WebSockets
- Service Workers y Aplicaciones Web Progresivas (PWAs)
- Introducción a WebAssembly
Módulo 8: Pruebas y Depuración
- Depuración de JavaScript
- Pruebas Unitarias con Jest
- Pruebas de Integración
- Pruebas de Extremo a Extremo con Cypress
Módulo 9: Rendimiento y Optimización
- Optimización del Rendimiento de JavaScript
- Gestión de Memoria
- Manipulación Eficiente del DOM
- Carga Perezosa y División de Código
Módulo 10: Frameworks y Librerías de JavaScript
- Introducción a React
- Gestión de Estado con Redux
- Conceptos Básicos de Vue.js
- Conceptos Básicos de Angular
- Elegir el Framework Adecuado