Una guía para principiantes de Redux

Entender Redux como principiante puede resultar bastante confuso. Redux tiene una gran cantidad de términos y conceptos nuevos que a menudo son bastante poco intuitivos. Esta guía presenta un ejemplo muy simplificado de una implementación de Redux. Definiré cada uno de los pasos y términos de una manera que tenga sentido para un principiante.

Esto pretende ser una guía para desmitificar los elementos de Redux. No contiene las definiciones técnicamente más precisas. No tiene las mejores prácticas. Tiene definiciones que ayudarán a desarrollar la comprensión de alguien sin conocimiento previo de estos conceptos. Existe una implementación simple para no confundir con detalles innecesarios.

El ejemplo que veremos en esta guía será una aplicación de tareas sencilla. La aplicación permite a un usuario agregar o eliminar elementos pendientes y verlos mostrados en la página.

Repararé paso a paso cada elemento de Redux, explicando qué es ese elemento y cómo implementarlo con ejemplos de código. Desplácese hasta la parte inferior para ver el ejemplo de código completo que mostrará cómo encaja todo como una aplicación React completa.

Resumen de pasos

  1. Escribe la función reductora
  2. Instancia de la tienda en el componente raíz
  3. Envuelva los componentes con el componente, pasando en la tienda como prop
  4. Escribe el componente
  5. Definir las acciones
  6. Defina el envío, adjúntelos al lugar donde se activarán los envíos (es decir, detectores de eventos, etc.)
  7. Definir la función mapStateToProps
  8. Exporte la función de conexión, pasando mapStateToProps y null como los 2 argumentos y pasando el nombre del componente en el segundo par de corchetes

Pasos

1. Escribe la función reductora

La función reductora es una función que le dice a la tienda cómo responder a las acciones. La función devuelve el estado nuevo y actualizado cada vez que se envía una acción. El estado es inmutable (no se puede cambiar) por lo que el reductor siempre devuelve un nuevo estado. El reductor generalmente usa el operador de propagación para insertar el estado actual en un nuevo objeto / matriz y agregarlo. La práctica común es usar una instrucción switch / case y verificar la propiedad type de la acción pasada. Luego, escriba el código que actualice el estado para cada caso.

Primero escribimos nuestra función reductora porque necesitaremos pasar esto cuando creemos una instancia de nuestra tienda. Sin embargo, comprender lo que está sucediendo requiere cierto conocimiento de las acciones y el envío. Cubriremos esto más adelante en esta guía.

Por ahora, sepa que nuestra aplicación de tareas deberá interactuar con la tienda de 2 formas: para agregar un nuevo elemento de tarea al estado y para eliminar un elemento de tarea del estado. Por lo tanto, escribimos nuestra función para que responda a 2 casos del tipo de acción. Utiliza el valor de la acción para agregar o eliminar un elemento de tarea del estado.

Al reductor se le pasan 2 parámetros: estado (este es el estado completo actualmente en la tienda, y le damos un valor predeterminado si el estado aún no existe) y la acción. Devolvemos el estado en el caso predeterminado.

2. Cree una instancia de la tienda en el componente raíz

La tienda es lo que realmente contiene el estado en ella. Es un poco mágico y realmente no necesitas conocer los entresijos de él. Todo lo que necesita saber es que no accede directamente como lo haría en un estado normal de React. Puede acceder a él y realizar cambios en él mediante reductores, acciones y despacho.

La otra cosa importante que debe saber sobre la tienda es que contiene algunos métodos útiles e importantes. El método principal es la función de envío. También contiene un método getState (para ver el estado) y un método de suscripción (ejecuta una devolución de llamada cada vez que se envía una acción).

Normalmente, la tienda se crea en la raíz de su aplicación (por ejemplo, App.js). Se almacena como una variable y se pasa el reductor como parámetro. Luego, la tienda se pasa como un accesorio al componente Proveedor.

Instalamos nuestro objeto de tienda pasando en el reductor que acabamos de crear.

3. Envuelva los componentes con el componente, pasándolo en la tienda como accesorio.

El proveedor es un componente creado para facilitar el paso de la tienda a todos sus componentes. El componente Proveedor envuelve todos sus componentes (por ejemplo, renderice sus componentes como hijos de Proveedor). Se pasa la tienda como un accesorio solo al Proveedor. Esto significa que no necesita pasar la tienda como un accesorio para cada componente, ya que cada componente lo obtiene del Proveedor. Sin embargo, esto no significa que los componentes todavía tengan acceso al estado. Aún necesita usar mapStateToProps (cubriremos esto más adelante) para tener el estado accesible en su componente.

Empaquetamos el componente Todo que vamos a hacer con nuestro componente Proveedor. Pasamos en la tienda que creamos en el paso anterior.

4. Escribe el componente

A continuación, comenzamos a escribir el componente Todo que renderizará los elementos de todo e interactuará con la tienda de Redux.

El componente es un componente con estado que contiene un elemento de estado para realizar un seguimiento de lo que el usuario ha escrito en la entrada. Tenemos una función llamada handleChange. Esta función actualiza el estado cada vez que el usuario escribe algo en la entrada. Hasta ahora esto es todo lo que escribiremos. Necesitamos entender más sobre Redux antes de poder escribir la lógica. La lógica agregará nuevos todos al estado y recuperará los actuales del estado para representarlos en la página.

5. Definir las acciones

Una acción es un objeto simple que contiene una propiedad llamada 'tipo'. Este objeto se pasa a la función de envío. Se usa para decirle a la tienda qué evento acaba de ocurrir (leyendo la propiedad del tipo de acciones). También indica qué actualización debería hacer al estado en respuesta (a través de la función reductora). La acción también puede contener otras propiedades para cualquier otro dato que desee pasar al reductor. Los datos solo se pueden pasar por aquí, por lo que cualquier dato necesario deberá pasarse aquí.

Usaremos creadores de acciones para definir nuestras acciones. Los creadores de acciones son una función que devuelve el objeto de acción. Su propósito es hacer que la acción sea más portátil y comprobable. No cambia el comportamiento de cómo funciona nada. Es otro método de escribir y transmitir la acción. También te permite pasar parámetros si quieres enviar datos con la acción que estaremos haciendo. Por lo que necesitamos utilizar creadores de acciones aquí.

Si recuerdas, nuestro reductor respondió a 2 tipos de acción: "ADD_TODO" y "REMOVE_TODO". Definiremos esas acciones con nuestros creadores de acciones. En nuestra acción add_todo devolverá "ADD_TODO" como el tipo y el elemento de tarea que queremos agregar a la tienda como el valor (necesitamos que la tienda agregue este elemento de tarea al estado para que se pase aquí). En remove_todo devolvemos “REMOVE_TODO” como el tipo y el índice del elemento de tarea pendiente en la tienda como valor. Necesitaremos esto para eliminarlo de la lista de todos.

Si vuelve a nuestra definición de función reductora, es de esperar que ahora tenga más sentido. Al leer action.type, el reductor sabe si necesita agregar una tarea al estado o eliminar una. Tiene el elemento de todo pasado en add_todo. Se agrega al estado actual utilizando el operador de propagación. En remove_todo usa el operador de propagación para crear una nueva matriz agregando el estado actual cortado dos veces, una vez con todos los elementos antes del que se va a quitar y la segunda con todos los elementos después del que se va a quitar, creando así nuestro nuevo objeto de estado con el Todo elemento eliminado.

Sin embargo, esto todavía no es una imagen completa. Todavía no hemos cubierto cómo se llama al reductor y cómo se pasa en la acción correcta. Para eso, tendremos que pasar a definir nuestra función de envío.

6. Defina el envío, adjúntelos al lugar donde se activarán los envíos (es decir, detectores de eventos, etc.)

La función de envío es un método de la tienda que se utiliza para provocar un cambio en el estado. Cualquier evento o cualquier cosa que necesite actualizar el estado debe llamar al método de despacho para hacerlo. Esta es la única forma de activar un cambio / actualización del estado. Se llama al despacho y se pasa el objeto de acción (o el creador de la acción, si se utilizó). Una vez que se activa un envío, la tienda llama a la función reductora y pasa la acción que proporcionó el envío que actualiza el estado, como hemos visto anteriormente.

A continuación definimos la mitad inferior de nuestro método de renderización de Componentes. Creamos nuestros botones que contendrán nuestros controladores de eventos. Dentro de ellos, definiremos nuestras funciones de envío.

El primer botón es un simple botón de agregar. Este botón enviará la acción add_todo a la tienda. Pasará la entrada del usuario actual como valor (este es el elemento de tarea pendiente que el reductor agrega al nuevo estado). Tenga en cuenta que llamamos despacho como this.props.dispatch. Está un poco fuera del alcance de esta guía comprender cómo y por qué esto se pasa como un apoyo al componente. Así que sepa que lo hace y podemos llamarlo así.

El segundo controlador de eventos está escrito como un onClick en nuestro elemento de tarea renderizado. Al hacer clic en cualquier elemento de tareas pendientes en la página, se activa un controlador de eventos. El controlador de eventos busca en la lista de tareas y encuentra el índice de esa tarea en la lista. Luego envía la acción remove_todo y pasa el índice.

El ciclo de cómo actualizar el estado en la tienda Redux ahora está completamente definido. Sabemos que cada vez que queremos cambiar el estado, debemos llamar al método de despacho, pasar la acción adecuada y asegurarnos de que nuestro reductor maneja esas acciones y devuelve el nuevo estado utilizando los valores que pasamos a través de la acción.

La única pieza del rompecabezas que falta ahora es cómo obtenemos el estado de la tienda Redux. Probablemente haya notado que he mapeado una lista llamada this.props.todosen el ejemplo anterior. Quizás se esté preguntando de dónde vino eso. También puede recordar que al principio de esta guía mencioné que pasar tienda al componente Proveedor no es suficiente para obtener acceso al estado de la tienda. Todo esto se aborda en los siguientes 2 pasos cuando definimos nuestra función mapStateToProps y la pasamos a la función de conexión.

7. Defina la función mapStateToProps

Cuando desee que su componente tenga acceso al estado, debe especificar explícitamente a qué estado tendrá acceso el componente. Su componente no tendrá acceso al estado sin esto.

mapStateToProps es una función que simplemente devuelve un objeto que define qué estado debe pasarse al componente asignando valores en el estado a las propiedades que usted define en este objeto. Esencialmente, el objeto que devuelve en mapStateToProps es lo que serán sus accesorios en su componente. La función mapStateToProps se pasa al método de conexión como primer argumento.

MapStateToProps toma el estado completo como parámetro y usted toma solo lo que necesita de él. Aquí aunque nuestro estado solo contiene la lista de todos. Necesitamos esa lista en nuestro componente ToDo, devolveremos el estado completo como una propiedad llamada todos.

Como puede ver ahora, tenemos acceso a toda nuestra lista de tareas en nuestros accesorios como this.props.todos. Así es como pudimos representar todos nuestros todos en el ejemplo anterior al mapearlo.

Finalmente, necesitamos pasar esta función a nuestro método de conexión para conectar todo.

8. Exporte la función de conexión, pasando mapStateToProps y null como los 2 argumentos y pasando el nombre del componente en el segundo par de corchetes.

Connect es un método que conecta las funciones mapStateToProps y mapDispatchToProps (ver a continuación) a su componente para que la tienda pueda leer esas funciones y asegurarse de que lo que definió allí se pase al componente como accesorios. Este método tiene una sintaxis especial que se ve así:

connect(mapStateToProps, MapDispatchToProps)(YourComponent)

Pasas las 2 map...ToPropsfunciones a la conexión y luego el nombre de tu componente dentro del segundo par de corchetes. Un patrón típico es exportar el método de conexión en lugar de su componente cuando está exportando su componente al final de su archivo. Por ejemplo:

export default connect(mapStateToProps, MapDispatchToProps)(YourComponent)

Esto entonces actúa de la misma manera que exporta normalmente, excepto que el estado y los envíos se pasarán como accesorios. mapStateToProps y mapDispatchToProps son en realidad parámetros opcionales para conectarse. Si no desea pasar uno o ninguno de los dos, coloque nulo en su lugar.

Quizás se esté preguntando de dónde viene esta función mapDispatchToProps y por qué no la hemos mencionado antes aquí. Bueno, como esta guía es el ejemplo más simplificado de una tienda Redux y mapDispatchToProps no es estrictamente obligatorio, no lo he incluido en nuestro ejemplo. Si no pasa mapDispatchToProps y pasa null en su lugar, aún puede acceder a la función de envío en su componente como lo hemos hecho anteriormente this.props.dispatch.

Entonces, para terminar nuestra aplicación de ejemplo, todo lo que tenemos que hacer es exportar nuestro componente envolviéndolo con la función connect y pasando el mapStateToProps que acabamos de definir.

¡Y eso es! Esa es una implementación completa de una tienda Redux. Vea a continuación el ejemplo práctico de lo que implementamos.

Ejemplo de código anotado completo

App.js Todo.js

Espero que esta guía pueda simplificar algunos de los detalles extraños y a veces confusos de Redux. No es una guía completa de Redux, ya que definitivamente hay más elementos y patrones para comprender. Pero si puede comprender esta guía, entonces está en camino de poder trabajar e instalar Redux en sus aplicaciones.