A tu propio ritmo

Explora nuestra extensa colección de cursos diseñados para ayudarte a dominar varios temas y habilidades. Ya seas un principiante o un aprendiz avanzado, aquí hay algo para todos.

Bootcamp

Aprende en vivo

Únete a nosotros en nuestros talleres gratuitos, webinars y otros eventos para aprender más sobre nuestros programas y comenzar tu camino para convertirte en desarrollador.

Próximos eventos en vivo

Catálogo de contenidos

Para los geeks autodidactas, este es nuestro extenso catálogo de contenido con todos los materiales y tutoriales que hemos desarrollado hasta el día de hoy.

Tiene sentido comenzar a aprender leyendo y viendo videos sobre los fundamentos y cómo funcionan las cosas.

Buscar en lecciones


IngresarEmpezar
← Regresar a lecciones
  • Flux

  • React.js

Editar en Github

Qué es React Flux

¿Por qué necesitamos Flux?

¿Recuerdas que siempre decimos que la programación es como Taco Bell? ¡Siempre son los mismos ingredientes utilizados de una manera diferente! En este caso particular, vamos a confiar mucho en los Eventos para crear toda la arquitectura de la aplicación.

¿Por qué necesitamos Flux?

Sabemos que todavía estás aprendiendo React. Los states (estados) y las props (propiedades) pueden ser confusos, y ahora, con Flux, las cosas se van a poner un poco más difíciles ¡Pero es por una buena causa!

Sin Flux, no puedes crear aplicaciones React medianas o grandes porque todo se desorganizará bastante rápido.

Además, dos vistas diferentes no pueden enviar datos entre sí como lo hacen los componentes (utilizando props) porque todas las vistas son hermanas y React Router las está instanciando. Necesitamos tener un store común compartido entre todas las vistas que vamos a llamar "The Store."

Aquí hay una lista de todas las ventajas de usarlo:

  • Centraliza y separa los datos de la aplicación de los componentes: la comunicación de la base de datos y el procesamiento de los datos ya no dependerán de cómo se vea la aplicación.
  • Controla la forma en que fluirán los datos de tu aplicación: no importa si los datos fueron ingresados por el usuario o provienen de una base de datos; todo estará disponible de forma clara y accesible.
  • Diferencia sus componentes en vistas vs componentes reutilizables: sus componentes seguirán siendo abstraídos desde la lógica de tu aplicación, haciéndolos 100% reutilizables para futuras aplicaciones.

React Flux

Flux divide la aplicación en 3 capas

  
Vistas/Views (Components)Cada componente React que llama a cualquier acción Flux es llamada una vista. La razón para llamar a esos componentes de una manera diferente es porque se supone que los componentes de React se comunican entre sí a través de sus props (sin Flux).

Una vez que un componente React esté hard coded a Flux, no podrás reutilizar ese componente en el futuro (en este o en cualquier otro desarrollo).
Acciones (Actions)Las acciones pueden ser activadas por componentes (cuando el usuario hace clic o interactúa con la aplicación) o por el sistema (por ejemplo, la funcionalidad de guardado automático). Las acciones son el primer paso de cualquier flujo de trabajo de Flux y siempre deben enviarse al Store.
StoreEl store contiene todos los datos de la aplicación. Maneja todo lo que recibe el despachador y determina la forma en que se deben almacenar y recuperar los datos.

Construyendo nuestra primera historia de usuario con Flux

El siguiente proyecto es una aplicación de To-Do List (lista de tareas) con 3 historias de usuario principales:

  • Crear tarea.
  • Mostrar la lista de tareas.
  • Eliminar tarea.

Para codificar esta lista de tareas tenemos que crear 4 archivos:

  1. Un componente para agregar tarea.
  2. Un componente para los items de la lista.
  3. Un archivo para las actions y el estado(store).
  4. El archivo principal donde integraremos todo.

Al final, trabajar con Flux tiene que convertirse en algo tan automático como andar en bicicleta.

react flux

Vamos a implementar una lista de tareas

1) Crearemos un reducer para implementar el patrón flux

Para poder tomar el control del flujo de los datos en nuestra aplicación utilizaremos un reducer para agrupar las funciones y la lógica de la aplicación (actions) junto con los datos que manejan y que tienen que estar disponible para los componentes (state).

Por ahora solo diremos que el reducer es una función que genera un estado nuevo cada vez que se ejecuta y lo que haga dependerá de la información que reciba en la función action. Esto nos permitirá llamar a las actions para actualizar el estado como lo indica el patrón flux. Para entender en detalle como funciona un reducer, puedes leer esté artículo donde lo explicamos a profundidad.

1// Esta es la función reducer 2const TaskReducer = (state, action) => { 3 // Dependiendo del type de la acción realiza una tarea distinta 4 switch (action.type) { 5 case "add": 6 return [...state, action.payload]; 7 case "remove": 8 let newState=[...state] 9 newState.splice(action.index, 1); 10 return newState 11 default: 12 return state; 13 } 14};

El siguiente paso es hacer que esta función esté disponible para todos los componentes de mi aplicación, para eso utilizaremos un contexto con el hook useReducer, el cual nos va a permitir crear el estado y la función actions para ponerla a disposición del resto de la aplicación.

1//TaskContext.jsx 2import { useReducer, createContext } from "react"; 3 4// Creamos el contexto vacío 5const TaskContext = createContext(null); 6 7const TaskReducer = (state, action) => { 8 // Aquí va el reducer que se definió anteriormente👆 9}; 10 11// Crearemos un componente que va a envolver nuestra aplicación en el contexto 12export function TaskProvider({ children }) { 13 // Creamos el state 'tasks' y el despachador 'taskActions' 14 // adicionalmente pasamos como estado inicial un arreglo vacío 15 const [tasks, taskActions ]= useReducer(TaskReducer, []); 16 return ( 17 {/* Creamos el contexto con nuestro state y actions */} 18 <TaskContext.Provider value={{tasks, taskActions}}>{children}</TaskContext.Provider> 19 ); 20} 21 22// Es necesario exportar el contexto para usarlo en otros componentes 23export default TaskContext;

Ya con esto tenemos listo nuestro contexto con las tasks, ahora solo falta envolver nuestra aplicación en este componente para empezar a utilizarlo.

1//index.jsx 2import React from "react"; 3import ReactDOM from "react-dom/client"; 4import App from "./App"; 5import { TaskProvider } from "./TaskContext.jsx"; 6 7ReactDOM.createRoot(document.getElementById("root")).render( 8 <React.StrictMode> 9 <TaskProvider> 10 <App /> 11 </TaskProvider> 12 </React.StrictMode>, 13); 14

Ahora solo queda llamar al contexto desde los componentes que necesiten hacer uso de nuestras tareas.

2) Empecemos por agregar una nueva tarea

Para ello usaremos un componente que muestre una caja de texto y un botón que realiza la acción de agregar la tarea, todo dentro de un formulario para facilitar el manejo del evento de envío(submit).

Todo esto es básico de un formulario en react, pero como queremos utilizar las actions del contexto, necesitamos llamarlo en el componente.

1import { tasks, useContext } from "react"; 2import TaskContext from "./TaskContext.jsx"; 3 4export default function AddItem() { 5 const { taskActions } = useContext(TaskContext); 6 // A partir de este punto tenemos disponibles las actions del reducer 7 // ... 8}

Para hacer uso de estas actions se llama a la función y se le pasa como parámetro un objeto con la propiedades de la acción que queremos realizar, siendo la mas importante type que indica la acción especifica a ejecutar. El resto de las propiedades son datos opcionales que pueden ser requeridos por la acción.

1// AddItem.jsx 2import { useContext } from "react"; 3import TaskContext from "./TaskContext.jsx"; 4 5export default function AddItem() { 6 // Hacemos uso del contexto y accedemos a la función 'taskActions' 7 const { taskActions } = useContext(TaskContext); 8 function handleAddTask(e) { 9 e.preventDefault(); 10 // Llamamos al actions especificándole 'type' 11 // asi como también la tarea que se va a agregar 12 let textbox = e.target.elements.task; 13 taskActions({ type: "add", payload: textbox.value }); 14 textbox.value = ""; 15 } 16 return ( 17 <li> 18 <form onSubmit={handleAddTask}> 19 <input name="task" type="text"/> 20 <button type="submit">+</button> 21 </form> 22 </li> 23 ); 24}

3) Ahora vamos a mostrar la lista

De la misma forma como accedemos a taskActions, también podemos acceder al objeto tasks que contiene el estado con la lista. Igual que antes, debemos hacer uso de useContext en nuestro componente.

1import { useContext } from "react"; 2import "./App.css"; 3import TaskContext from "./TaskContext.jsx"; 4import ListItem from "./ListItem.jsx"; 5import AddItem from "./AddItem.jsx"; 6 7export default function App() { 8 // Accedemos al contexto, pero esta vez solo vamos a usar 'tasks' 9 const {tasks} = useContext(TaskContext); 10 11 return ( 12 <main> 13 <h2>Todo list</h2> 14 <ul className="list-group w-50"> 15 <AddItem /> 16 {tasks.map((task, index) => ( 17 <ListItem key={index} task={task} index={index} /> 18 ))} 19 </ul> 20 </main> 21 ); 22}

Puedes notar que aparece el componente AddItem que vimos previamente y desde donde se pueden agregar tarea. Luego de eso se hace el renderizado de la lista con la función map, pero notamos que se esta usando un componente ListItem para mostrar los elementos, no solo eso sino que ahi también corresponde hacer la eliminación de la tarea, veamos ese componente.

4) Eliminación de items

Si bien el renderizado es básico (un elemento li con el texto y un botón), lo interesante es como hacemos la eliminación del item con las actions.

Todo comienza cuando el usuario haga clic en el icono de la papelera. Es por eso que necesitamos iniciar nuestra aplicación escuchando el típico evento onClick en el botón de eliminar.

1 onClick={() => taskActions({ type: "remove", index })}

Notamos que el llamado al action es parecido al que usamos para agregar items, pero se le esta pasando un parámetro distinto llamado index, que le indica al dispatcher que elemento va a eliminar. Asi como vimos en ambos ejemplos, podemos pasar la data que necesite nuestra action al momento de llamarla como parámetros adicionales.

1import { useContext } from "react"; 2import TaskContext from "./TaskContext.jsx"; 3 4export default function ListItem({ task, index }) { 5 const { taskActions } = useContext(TaskContext); 6 7 return ( 8 <li> 9 {task} 10 <button 11 onClick={() => taskActions({ type: "remove", index })} 12 > 13 {/* Icono de papelera */} 14 <i className="bi bi-trash3"></i> 15 </button> 16 </li> 17 ); 18}

Resultado final

Ya hemos implementado la lógica de nuestra aplicación en un contexto aplicando el patrón flux, permitiendo su uso en distintos componentes. A continuación podemos ver el resultado final.