Comenzando con React-Redux

Déjame preparar el escenario: has creado una gran idea para una aplicación web y has decidido construirla con React. A modo de ejemplo completamente arbitrario, digamos que es un buscador de acordes de guitarra con un mástil de guitarra interactivo y una forma de presentación (como, por ejemplo, esta).

¡Auto promoción sin vergüenza!

Hiciste un par de listas de cosas para hacer, viste un par de tutoriales y crees que ya tienes el truco de todas estas cosas “de utilería”, así que te pasas directamente. Está yendo lo suficientemente bien, tienes tu parte superior nivel de componente de la aplicación, tal vez una forma, un componente de guitarra … y luego, comienza a aparecer en ti. Necesitarás una guitarra … con seis cuerdas … con doce trastes cada una … que necesitan comunicar información sobre si están silenciadas, presionadas o abiertas … que necesitan poder comunicarse con la forma y expresarse un acorde … Antes de que te des cuenta, han pasado seis horas, hay historias en todas las paredes, y estás bastante seguro de que has descubierto una conspiración que implica inexplicablemente a personas completamente ficticias y al Servicio Postal de los Estados Unidos.

Nota al pie para los fanáticos de Always Sunny, ¿alguna vez notaron que “Pepe Sylvia” suena muy parecido a cómo una persona analfabeta intenta leer “Pennsylvania”? Ese es el tipo de comedia sutil que necesitamos.

Pero no te preocupes (juego de palabras)! Hay una herramienta genial llamada Redux de la que quizás haya oído hablar, y está diseñada para escenarios como este, cuando el anidamiento de los componentes está fuera de control y los accesorios se pasan a izquierda y derecha. Podría decirse que está a punto de desaparecer, gracias a la recién actualizada Receta API de React y otras bibliotecas competidoras, y tiende a despertar sentimientos apasionados entre los desarrolladores que tienden a pensar alternativamente que es lo mejor desde un pan rebanado o un lío ofuscante impío, pero definitivamente todavía tiene su lugar.

La regla de oro con respecto al uso de Redux, de sus creadores y desarrolladores en todo el mundo, es algo parecido a “Si no estás seguro de si necesitas Redux, probablemente no”. A esa gente le digo … bueno, es probable que estés derecho. Redux hace añadir un montón de complejidad y repetitivo para tareas simples, que pronto vamos a averiguar. Y, como una cuestión de hecho, yo hice construir esta aplicación guitarra con regularidad edad reaccionar, y funcionó bien. Pero, era joven e ingenuo entonces (hace dos meses), así que, por una explicación, descubramos cómo podría habernos hecho la vida más fácil. Una vez que sacamos la plantilla, Redux tiene la capacidad de hacer que sus aplicaciones sean más escalables, más eficientes y más fáciles de depurar y razonar. Además, ¡me gusta mucho!

Representación de un artista de una aplicación React. ¿Quién tiene tiempo para todo ese anidamiento?

Así que supongamos que tienes una aplicación React todo construido. Si no, echa un vistazo a uno de los muchos buenos tutoriales que existen . Incluso intente crear-reaccionar-aplicación si lo desea. Una vez que esté funcionando, lo primero que querremos hacer es instalar nuestros paquetes.

sudo npm instalar redux 
sudo npm instalar react-redux

Los lectores astutos pueden notar que estamos instalando tanto Redux como una versión específica de React, ¿qué ocurre? Bueno, Redux es en realidad una biblioteca agnóstica. Puedes usarlo con Backbone, Mithril, Angular, Meteor o Vue. ¡Funcionará con todos! La versión específica de React, sin embargo, tiene algunos métodos que serán muy útiles para nosotros cuando estamos configurando nuestros componentes.

Con las instalaciones fuera del camino, vamos a configurar nuestra estructura de archivos, que tiene algunas piezas más de lo que estamos acostumbrados en una aplicación tradicional de React. Todo el mundo lo hace de forma un poco diferente, pero normalmente me gusta crear una carpeta de acciones , una carpeta de reductores y una carpeta de tiendas dentro de mi directorio react-client / src, de esta manera:

Puede ver que algunas personas usan constantes, no me molesto con ellas.

¡Estupendo! Comencemos con la tienda  : esto es lo que hace que Redux funcione. Puede considerarlo como un contenedor de estado externo con el que los componentes de React pueden interactuar directamente mediante algunos métodos especiales, independientemente de su nivel de anidación en la jerarquía de un proyecto. ¿Necesitas un poco de estado? Ve a la tienda ! ¿Necesita actualizar el estado? ¡Envíe una acción a la tienda ! ¡Todo está conectado!

Así es, utilicé la misma referencia dos veces en un artículo. Es … una metáfora de cómo Redux te hace escribir lo mismo en algunos lugares de tu aplicación … o algo así.

Hagamos un archivo index.js dentro de nuestra carpeta de la tienda . Primero, importaremos Reaccionar, entonces tenemos acceso a él – tiene sentido. A continuación, importaremos dos métodos directamente de Redux: createStore y combineReducers. ¡Estos harán exactamente lo que suenan! Sin embargo, ¿qué son los reductores y por qué los estamos combinando? Pongamos esa pregunta en espera, excepto para decir que también vamos a importar nuestro archivo reductionrs.js , que aún tenemos que hacer en nuestra carpeta de reductores . Después de todas nuestras declaraciones de importación, vamos a crear una variable llamada store y combinar nuestros reductores dentro de ella con combineReducers,que toma un objeto como argumento y se convertirá en nuestro estado de aplicación global Ponlo todo junto, y se ve como a continuación.

La línea 9 es exclusivamente para usar la excelente extensión de navegador de Redux. Lo recomiendo encarecidamente, pero no es obligatorio.

Todavía hay una pieza faltante: componente proveedor de Redux . Este es un contenedor de contexto que debe rodear toda su aplicación y que recibe la tienda como una propiedad, permitiendo que todos sus otros componentestengan acceso a ella a través de los métodos de Redux. En el nivel más alto de nuestra aplicación, nuestro archivo index.jsx al que adjuntamos React to the DOM, simplemente importaremos la tienda , el proveedor y nuestro componente de la aplicación (que crearemos en un segundo) y armar todo, como tal.

De esta forma, ¡toda nuestra aplicación tiene acceso a nuestra tienda!

Ahora que tenemos nuestra tienda configurada, hablemos sobre el resto del ecosistema de Redux. Esta es la parte más complicada, así que tengan paciencia conmigo. Efectivamente, usted tiene una relación circular que va a Store -> Components -> Actions -> Reducers -> Store (se ve debajo en forma de diagrama).

El estado de la tienda se asigna a un componente a través de una pequeña función llamada mapStateToProps  ; puede pensar en esto como un servicio de suscripción. De hecho, el método nativo de Redux que utiliza se llama suscripción (aunque en realidad no lo utilizaremos directamente en este tutorial). Cualquier cambio realizado en la tienda se reducirá a cualquier componente que se haya suscrito a esa propiedad en la tienda , lo que provocará una nueva presentación. Limpio, ¿eh?

Sin embargo, para afectar el estado de la aplicación, un componente tiene que usar una función separada: mapDispatchToProps . El envío es otro método de tienda , que toma una acción (que importamos) y la envía a un reductor , que recibe esa acción y realmente cambia el estado de la aplicación. Sé que es un bocado, pero vamos por pasos, comenzando con un componente súper simple . Este será nuestro componente de aplicación de más alto nivel , y también importará un método conocido como bindActionCreators de Redux, así como un método llamado connectde React-Redux. El primero solo hace que escribir nuestro mapDispatchToProps funcione un poco más limpio, mientras que el último es un componente de orden superior que agrupa nuestro componente con mapStateToProps y mapDispatchToProps para que estos métodos tengan acceso a la tienda . Esto es:

Observe cómo estamos importando nuestra acción en la línea 5 .

Aquí hay otros pequeños puntos de orden: observe cómo mapStateToPropstoma el estado de la aplicación como parámetro y cómo extraemos las propiedades individuales de ese estado. Estas propiedades estarán accesibles en los accesorios de ese componente , así que si quisiéramos obtener examplePropOne , lo haríamos así en la función de renderizado de nuestro componente (observe la etiqueta <p>):

render () { 
    return ( 
        <div> 
            <h1> ¡Hola mundo, este es un tutorial de Redux! </ h1> 
            <p> Aquí tenemos nuestra propiedad: {this.props.examplePropOne} </ p> 
        </ div> 
    ) 
}

De esta manera, cualquier cambio realizado en examplePropOne, incluso si proviene de otro componente , fluirá y se representará en este componente . No tiene que seleccionar todas las propiedades del objeto de estado en su función mapStateToProps , ¡solo ingrese las que le interesan a su componente!

mapDispatchToProps , de forma similar, toma en despacho como un parámetro. El envío es un método especial de la tienda Redux , y al asociar nuestra accióncon bindActionCreators , ambos lo conectamos a los accesorios del componente y decimos que, cada vez que se invoca, enviará la acción en cuestión al reductor para ser finalmente convertido en estado en la tienda .

Aquí hay un ejemplo de cómo podría verse eso en una función en el mismo componente:

exampleFunction () { 
    this.props.exampleAction (); 
}

¿Aún conmigo? Lo último a tener en cuenta en el componente es la sintaxis del método de conexión : siempre tomará dos argumentos, y siempre serán mapStateToProps y mapDispatchToProps , en ese orden. Puede omitir mapDispatchToProps fácilmente, pero si desea omitir mapStateToProps en un componente específico , asegúrese de dejar un valor nulo en su lugar. El nombre del componente en sí mismo debe invocarse al final de la declaración de conexión . Aquí hay otro ejemplo, esta vez escrito sin mapStateToProps y con un componentellamada Lista :

export default connect (null, mapDispatchToProps) (Lista);

Hasta ahora nos hemos ocupado de la tienda y las partes componentes del ciclo de vida de Redux. Eso solo deja acciones y reductores .

Las acciones son la parte fácil: solo son funciones que crean objetos JavaScript, con una propiedad obligatoria llamada tipo . Por convención, el tipo generalmente se escribe con mayúsculas y es muy descriptivo de lo que realmente hace esa acción . A menudo tiene otra propiedad llamada carga útil, en la que ponemos todos los datos reales pasados ​​a la acción . En general, queremos evitar incluir cualquier lógica de aplicación real dentro de estas acciones : simplemente deberían entregar un tipo y potencialmente algunos datos. Así es como se vería nuestro archivo actions / actions.js :

Observe cómo la segunda acción recibe un argumento, que pasa como una carga útil.

¡Eso es todo lo que hay para las acciones !


En este punto, solo nos queda un elemento en nuestro ciclo de vida: reductores . Un reductor es efectivamente una declaración de cambio gigante que toma una acción y, según su tipo , actualiza el estado de la aplicación. Si recuerda, cuando creamos nuestra tienda arriba, importamosnuestros reductores y los pasamos a través de combineReducers en nuestra función createStore , lo que significa que cualquier devolución de nuestros reductores actualizará el estado de la tienda . Esos cambios fluirán a través de cualquier función mapStateToProps que colocamos en nuestros componentessuscribirse a la tienda , y nuestros datos estarán completamente vinculados. ¡Eso es Redux! ¡Lo hicimos!

Ahora, hay un concepto importante que he omitido hasta ahora; de hecho, es uno de los conceptos fundamentales más importantes en Redux: la inmutabilidad . En pocas palabras, con Redux, a los efectos de una depuración más sencilla, un código limpio y único y una aplicación más eficaz, nunca cambiamos el estado de la aplicación directamente. En cambio, cada cambio de estado único se registra como una instantánea en el tiempo, y cada cambio se realiza en una versión copiada del estado. Para un ejemplo más obvio de cómo esto es útil, tome las herramientas de desarrollo de Redux aludidas anteriormente: mantiene un registro de todo el historial de estado en el ciclo de vida completo de la aplicación para que pueda ver paso a paso cómo y cuando las cosas están cambiando Súper útil! Recomiendo encarecidamente si tienes tiempo.

Dicho todo esto, aquí hay un ejemplo de cómo se vería un reductor , es decir, una función que toma en cuenta el estado de la aplicación, así como las acciones entrantes , lo ejecuta a través de una instrucción switch y devuelve la versión actualizada del estado a entregar a la tienda :

No tenemos que proporcionar el estado predeterminado como lo hice en este ejemplo: en algunas aplicaciones, definirá un estado predeterminado en un archivo diferente, le dará propiedades de inicialización y luego lo importará a su reductor . En otras aplicaciones, puede simplemente inicializar el estado como un objeto vacío utilizando el parámetro predeterminado de ES6. No existen reglas estrictas para inicializar el estado, excepto que debe definirse, y su reductor siempre debe devolver un estado. Para ese propósito, también es muy importante que no olvidemos nuestro caso predeterminado en la línea 18.

Fundamentalmente, el reductor debe tomar en un objeto de estado y una acción como argumentos, configurar un interruptor en la acción ‘s Tipo depropiedad, y luego devolver una versión copiada del estado con las propiedades deseadas actualizados. Tenga en cuenta los operadores de difusión en las líneas 10 y 15: estos separan el estado anterior antes de agregar y / o modificar las propiedades deseadas, lo que significa que terminará devolviendo una versión copiada, ligeramente modificada del estado a la tienda con cada acción . También puedes hacer esto usando Object.assign, pero el operador de spread me parece más elegante. Tenga en cuenta también cómo en la línea 16 estamos usando la carga útil de la acciónpropiedad para entregar datos en nuestro estado, mientras que en la línea 11 estamos codificando una modificación en examplePropOne .


Hay un poco más de lo que podríamos hablar cuando se trata de React-Redux. Tomemos, por ejemplo, las acciones asíncronas: pasar los resultados de las llamadas a la API, operaciones que la mayoría de las veces son bastante sencillas, pueden causar un dolor de cabeza si se tienen acciones que requieren ciertos criterios antes de la ejecución. Hay una biblioteca llamada redux-thunk para ayudar a lidiar con eso. También puede tener múltiples reductores en un proyecto, que luego pasaría a través de la función combineReducers en su archivo de tienda . Además, el estado local aún puede ser realmente útil en componentes individuales , y realmente solo debería involucrar a la tiendaen los casos en que se pasa el estado entre componentes anidados Los animo a que lean más y comiencen a experimentar para aprender todos los puntos finos de Redux, y para leer acerca de las soluciones de administración del estado que compiten entre ellas, mobx y la ya mencionada Context API.

En este punto, sin embargo, espero que puedan ver cómo Redux podría hacer que nuestra aplicación de guitarra sea un poco más simple. Supongamos que un usuario hace clic en un traste, y debemos actualizar la cadena en la que se encuentra, el componente de la guitarra , el componente de la aplicación y el componente del formulario . En lugar de pasar alrededor de los APOYOSpor todo el lugar, a través de múltiples niveles en los que no puede incluso ser utilizado, que puede en lugar de enviar una sola acción y establecer un par de suscripciones y somos buenos para ir! En aplicaciones especialmente grandes con mucho anidamiento y mucho estado para administrar, esto puede simplificar mucho tu vida y es una posible solución a un problema muy complicado.

Si has llegado hasta aquí, ¡gracias por leer! Aquí hay un lindo hurón como agradecimiento.

Leave a Reply

Your email address will not be published. Required fields are marked *

Ir a la barra de herramientas