This graph shows how many times the word ______ has been mentioned throughout the history of the program.
Vamos a ver un poco Redux desde cero y vamos a ver justamente por qué digo que es totalmente agnóstica a la UI.
Como he dicho, es una biblioteca y es un patrón.
Es una biblioteca que te puedes instalar, pero también es un conjunto de patrones de cómo debes tratar el estado de tu aplicación.
Y esto es muy interesante, porque al ser un patrón, en realidad al final puedes hacer un Redux sin Redux.
Pero bueno, estos patrones, digamos que tienes unas palabras claves que tienes que entender.
Justo como hemos visto en la imagen esta, pues hay unas cuantas palabras que tenemos que dominar.
Las acciones, el dispatcher, el store, y vamos a ver un poco en qué se convierte cada una de estas cosas.
Por ejemplo, vamos a crear nuestra aplicación que sea un contador y de cómo podríamos utilizar Redux para manejar la lógica de la actualización del estado de nuestro contador.
Lo primero que tendríamos que conocer son los reducers.
Cuando hablamos de un reducer, es como tomar algo de entrada y convertirlo en otra cosa.
Esto es exactamente el reducer que tenemos en un array, ¿no?
Vale, tienes un array y te lo voy a transformar en otra cosa.
¿Qué puede ser un array?
Puede ser un número, puede ser un objeto, puede ser un montón de cosas.
Exactamente lo mismo tendríamos con el reducer.
Tendríamos con el reducer de Redux.
Pongamos un reducer.
El reducer, al final, lo que le llega es el estado y una acción.
Y a partir de esto, lo que tiene que expulsar es el nuevo estado.
Toma, tienes este estado.
Al final, también tienes esta acción, este evento que ha ocurrido.
Dime cuál es el nuevo estado de mi aplicación.
Al final, el más sencillo que puedes crear sería tal que así.
Esto sería un reducer.
Un reducer que, como parámetros, le llega un estado y le llega una acción y lo que hace es devolver el mismo estado.
Es el reducer más inútil del mundo, cierto es, pero al fin y al cabo es un reducer.
Lo que pasa es que simplemente no hace absolutamente nada, ¿verdad?
Esto podría ser un reducer, así que lo vamos a utilizar así.
Vamos a poner esto en minúscula.
El reducer, nuestra máquina de estado por ahora.
Luego veremos cómo lo podemos ir mejorando.
Claro, ahora mismo, si yo le digo que el estado es cero, ¿no?
Imaginad que el estado, al final el estado de nuestra aplicación puede ser lo que nosotros queramos.
Normalmente es un objeto, pero en este caso vamos a empezar con un número para hacerlo un poco más sencillo, ¿no?
Queremos hacer un contador, pues vamos a ver que tengamos justamente el estado que sea un contador, que empieza desde cero.
¿Qué acciones vamos a tener?
Pues vamos a tener una acción que sea, por ejemplo, incrementar.
Esto podría ser una acción, pero ¿cómo se definen las acciones?
¿Qué son estos eventos que le podemos decir a Redux qué han ocurrido y cómo se lo indicamos?
Normalmente las acciones son, en realidad, objetos.
Y en los objetos le podemos decir, esto sería una acción.
Y esta acción tiene, ¿qué tipo es la acción?
Pues podemos decir que esto es el counter que ha sido incrementado.
Pénsate en las acciones que también son como los eventos que han ocurrido y que le tenemos que decir,
ha ocurrido este evento y a partir de este evento tienes que cambiar algo en el estado global de tu aplicación.
Así que tendríamos esta acción, pero esto no es una acción cualquiera.
Esta sería la acción de incrementar, ¿no?
Pues ahora, al utilizar esta acción, ¿qué es lo que esperaríamos de nuestro Reducer?
Una vez que a nuestro Reducer le decimos, mira, este es el estado, cero, pero quiero que incrementes.
¿Qué es lo que debería ocurrir, no?
Ya empiezan a jugar entre sí dos palabras, ¿no?
Una, los Reducers y otra, las acciones.
El Reducer le está diciendo, vale, yo soy la máquina, pero dime qué ha pasado.
Ah, pues que se ha incrementado el contador.
Ah, ok, pues ahora que me has dicho que se ha incrementado el contador, voy a hacer algo al respecto.
Pues vamos a verlo aquí.
Una vez que en el counter Reducer nosotros tenemos la acción, lo que vamos a decir, vale,
pues vamos a recuperar qué tipo de acción ha llegado y si el tipo de acción es justamente esta de aquí,
pues lo que vamos a hacer es decirle que el estado que tiene que devolver es estado más uno, ¿no?
Porque es cero y por lo tanto lo que esperamos de aquí, esto por ahora lo podría hacer en el Run.js.
El Run.js al final lo que hace es que puedes ver aquí en la consola la evaluación de esa línea, ¿no?
Ahora que tenemos el Reducer le decimos, vale, recuperamos la acción, el tipo de la acción cuando se ha incrementado,
entonces el estado es más uno.
Y le hemos pasado aquí que el estado es cero, o sea que cuando el estado es cero e incrementa,
pues tienes que decirme que es uno.
Aparte de incremente tendríamos acción decremente, esta podría ser otra.
Tenemos una acción que esto lo que dice es que nuestro counter ha sido decrementado.
Entonces cuando tú ejecutas esto y lo ejecutamos aquí con el uno,
pues ahora justamente si hacemos la acción decrementada, pues esto debería ser un cero.
¿Qué pasa que sigue siendo un uno?
¿Por qué?
Porque todavía aquí en el Reducer no entiende este evento, por lo tanto tenemos que decirle, vale,
pues si el tipo es igual a counter decremented, entonces devuelve un estado menos uno.
Ya tendríamos aquí entonces que aquí cuando el cero lo incrementamos se devuelve en uno,
el counter cuando lo decrementamos se vuelve en cero.
Esto justamente que nos devuelve el new state, esto se lo podríamos pasar aquí.
Tenemos aquí el new state, así ya lo podríamos reutilizar.
Y así de esta forma vamos generando ese estado y volviéndolo a crear.
Igualmente por ahora lo vamos a dejar así, vamos a confiar en nuestro Reducer.
Ya os digo que los Reducers, que podéis ver aquí, esto no funciona así y no lo vamos a ver nunca en nuestra aplicación.
Nunca se utiliza directamente.
Pero en este caso nos va a ayudar a comprobar que funciona.
Vamos a pensar en otra acción, ¿vale?
Action, Reset.
Vamos a llamarle Reset, Reseted.
Vamos a ponerlo este y vamos a hacer que cuando se resete el state vuelva a cero.
Fíjate que una cosa que estoy haciendo aquí es que no estoy cambiando el estado.
Lo que estoy es devolviendo un nuevo estado, ¿no?
Aquí lo que estoy haciendo es, vale, yo te paso esto, pues te devuelvo un nuevo estado.
Siempre te devuelvo un nuevo estado.
Esto siempre es como funciona.
Verás muchas veces que los Reducers no se suelen trabajar con if, if, if.
Nunca, no se suelen hacer así.
Lo que se suele utilizar es un switch.
Podemos utilizar un switch que sea un poquito más fácil de leer.
De forma que en caso que sea esto, pues entonces hacemos el return state más uno.
Y esto lo podríamos hacer con todos los casos, ¿no?
Este podría ser otro, ¿vale?
En caso este.
Y nos falta el reset.
Entonces ya tendríamos esto con nuestro switch.
Y esto es la forma más típica que vas a ver un Reducer, ¿vale?
En lugar de verlo así, normalmente lo vas a ver más bien así.
De forma que vas a ver un switch que dices, vale, cuando el action type, en el caso que sea este, haces esto.
En el caso que sea esto, haces esto.
Esto sería el switch típico de un Reducer.
Pero os he dicho que este Reducer, esto nunca se utiliza así.
La siguiente palabra que tienes que conocer, ahora que conoces las acciones y el Reducer, es la store.
La store al final es un objeto que reúne las actions y los Reducers.
Y tiene diferentes responsabilidades.
Tiene la responsabilidad de contener el estado de la aplicación.
Permite leer el estado de la aplicación.
También permite que actualices el estado de la aplicación.
En lugar de utilizar el Reducer de esta forma, va a ser la store la que tenga la responsabilidad de llamar él al Reducer,
como tenga que llamarlo.
Y no tendrás que hacer tú nada más de esto.
Vamos a traernos un Create Store desde Redux.
Y fíjate que vamos a importar Redux.
Hasta ahora no estamos utilizando Redux para nada.
Una cosa que tenemos que hacer para crear la store es pasarle cuál es el Reducer que tiene que utilizar la store.
Así que le vamos a decir, vale, vamos a crear una store con el Create Store.
Y le vamos a decir cuál es la máquina que tiene que utilizar a la hora de gestionar el estado cuando le lleguen las acciones.
Nuestro caso es el Counter Reducer.
Aquí lo tendríamos ya.
Así que ahora es la store la que tiene esta responsabilidad.
Ahora es la que sabe cómo tiene que actualizar el estado.
Por lo tanto, ya no tendríamos que utilizar nada de esto.
Estos Counter Reducers que estamos haciendo aquí.
Obviamente, estas acciones sí que las necesitamos.
Normalmente está separada en otro archivo.
Ahora que ya tenemos la store y tenemos aquí las acciones, ¿cómo tenemos que hacer esto?
Pues tenemos que utilizar un store.dispatch.
El dispatch es ese dispatcher que hemos visto antes.
A las acciones hay que despacharlas y hay que enviárselas a la store.
Entonces, lo que tenemos que decirle es que a la store le vamos a enviar un evento.
¿Y qué evento le vamos a decir?
Pues podríamos hacer aquí.
Por si no queremos utilizar esto de type aquí.
Esto lo he puesto antes así, pero se puede pasar aquí directamente.
Store.dispatch y le pasamos justamente qué acción es la que queremos hacer.
También lo podríamos hacer de la forma que la habíamos hecho antes.
Con Action Incremented.
Le decimos, vale, pues envía esto.
Ahora, una vez que ya le ha llegado esto, ¿cuál es el estado que tiene nuestra aplicación?
¿Cómo lo sabemos?
¿Cómo podemos saberlo?
Pues podríamos llamar a la store y decirme, vale, quiero recuperar el estado.
Pero fíjate que me da un none.
¿Por qué me da un none?
¿Por qué me da un notanumber?
¿Qué ha pasado aquí?
Vamos a revisar bien esto, ¿no?
Yo he creado la store con el counter reducer.
Aquí tengo el estado.
Tengo la acción.
Le digo el tipo.
Pero cuando le digo que me incremente, cuando me digo el tipo de incrementar, me dice que cuando recupera el estado es none.
¿Y cómo puede ser esto?
Lo que está pasando aquí es que si te fijas bien, el estado no está definido.
El primer estado con el que empezamos nuestra aplicación no está en ningún sitio.
O sea, no lo estamos encontrando.
Así que cuando está incrementando, ¿qué incrementa?
Claro, antes cuando utilizamos el counter reducer y ya le decíamos cuál era el estado que teníamos, claro, así más fácil.
Pero ahora, ¿qué está ocurriendo?
Que cuando intenta incrementar, fíjate, entra aquí, pero state es undefined, no se lo estamos pasando.
Entonces, no está empezando en ningún momento a tener un estado inicial.
Se lo tenemos que indicar.
De forma que si no le pasamos un estado, vamos a decirle que el estado inicial sea cero.
Y a partir de aquí, cuando el estado inicial es cero, ya estamos empezando la rueda.
Este estado inicial es cero, cuando lo incrementamos es uno.
Pero la siguiente vez que le incrementemos y hagamos un store getState, ahora deberíamos ver que la siguiente vez que lo incrementamos es dos.
Porque ya está empezando la rueda, ya se está guardando este estado, ya está funcionando como debería.
En este caso, lo estamos haciendo con un tipo primitivo, con un número.
Pero luego veremos que esto se va a ir complicando, ¿vale?
Pues esto podríamos ir recuperando cada vez que hacemos una acción, ¿no?
Pues ir recuperando el estado e ir viendo cómo esto va funcionando.
Y sin ningún problema, pues uno, dos, tres y así hasta el infinito, ¿no?
Podríamos ir haciendo un dispatch constantemente de esto.
Otra cosa que podemos hacer, en lugar de hacer un getState cada vez que hacemos un dispatch, vamos a hacer aquí.
Lo que puedes hacer es suscribirte.
De forma que cada vez que tú recibas un cambio, pues puedes hacer un store.getState.
Pues entonces, yo aquí lo que me estoy suscribiendo es justamente a la store.
Y cada vez que detecta un cambio en la store, pues hago un getState.
Entonces, por eso pego aquí un 1, un 2 y un 3.
Esto es interesante porque esto es lo que le va a permitir justamente, nos va a permitir actualizar la UI cada vez que encontremos un cambio en el estado.
De forma que podamos reflejar en algún sitio que ha cambiado el estado, ¿vale?
Entonces, lo que podemos hacer es que cada vez que hagamos un dispatch, pues vamos a hacer aquí un document.body.innerHTML.
Y vamos a hacer aquí un store.getState.
Ahí ahora mismo lo que tenemos es el botón cada vez que se ha hecho un dispatch.
Podríamos añadirle un botón de forma que cada vez que hagamos clic en el botón, hagamos un dispatch para incrementar o para resetear o lo que sea.
Así que vamos a hacer eso en un nuevo proyecto y lo vamos a hacer con React.
React ReduxApp.
Esto lo vamos a dejar.
Import React.
ReactDome.
Tenemos el import del CreateStore.
Aquí se nos está quejando de una cosa que es interesante que ahora lo vamos a arreglar.
Luego, el ActionDecremented, porque no lo estoy usando, pues se está quejando.
Tenemos el store.subscribe.
Tenemos los dispatch.
Ahora vamos a arreglar un poco esto para ver cómo lo podemos hacer.
Tenemos aquí un ReactDome.
Tenemos aquí una app.
Vamos a hacer que renderice el div y vamos a hacer que renderice el getState.
Vamos a arreglar esto.
Aquí, en los switch, es interesante siempre tener un default, porque imagínate que por lo que sea le pasas una acción que aquí no está y que no lo está soportando.
Pues es una buena idea tener un default y aquí tiene dos opciones.
Una, devolver el mismo estado o lo que puedes hacer, dices, oye, no, es que esto es un error y es not supported.
Depende de lo que quieras hacer, ¿vale?
En este caso vamos a devolver el estado, vamos a mantenerlo sencillo.
Estas acciones vamos a ponerlas un poco más arriba, vamos a ponerlas aquí.
Ahora, estos dispatch, todo esto que habíamos hecho, esto no lo vamos a hacer así.
Vamos a renderizar esta aplicación, que es recuperar el estado.
Deberíamos ver que es un cero.
Este es el cero porque es nuestro estado inicial, pero vamos a arreglar esto, que esto no es lo que nos interesa.
Ahora va a haber un poco más de hechiza, porque esto es el estado inicial, tenemos un div, vamos a ponerle aquí unos botoncillos, ¿no?
Que funcionen y que hagan un poquito de magia.
Venga, que cuando le utilicemos este un clic, vamos a ejecutar el store.dispatch y aquí pues vamos a utilizar el incremente.
Por ejemplo, ahora esto sería, vamos a poner un más.
Vamos a ponerle tres botones.
Este sería el action decremented y este sería el action reset.
Aquí sería un menos.
Hasta aquí esto debería funcionar.
Voy a refrescar, tengo el más, el menos, el reset, pero le doy y no pasa nada.
Porque si miro el subscribe que tengo aquí, o sea que está funcionando, pero no se está reflejando en la UI.
El problema es que de alguna forma React no está inteligente de que tú cambias el estado y ya está.
Por ahora, una cosa que podemos hacer fácilmente para ir por faena, voy a simplificar un poco esto.
Vamos a dejar así.
Este react.dome.render ahora mismo solo se está ejecutando una vez.
Voy a utilizar aquí una función que se llama renderup.
Este método lo voy a ejecutar una primera vez y lo voy a ejecutar cada vez que cambie el estado.
Voy a hacer que se suscriba y que ejecute este renderup.
Podríamos hacerlo así, renderup, podríamos hacerlo así, pero como ya sabemos que las funciones son de primera clase en JavaScript y podemos pasar referencias, vamos a ejecutarla así que queda más pro.
¿Qué es lo que estamos haciendo?
Vamos a renderizar nuestra aplicación por primera vez y nos vamos a suscribir que cada cambio que tenga la store vuelva a renderizar la aplicación.
Ya veremos que esta no es la mejor forma de hacerlo.
Más adelante veremos seguramente en la siguiente clase utilizar React Redux, cómo utilizarlo correctamente y todo esto.
Vamos a ver si esto funciona.
Ahora sí.
¿Vale?
Ves que le doy a menos, le doy a más y entonces esto sí que funciona.
Se está volviendo a renderizar la aplicación porque cambia el estado y ahora pues nada, cada vez que le damos pues funciona sin ningún tipo de problema.
Esto lo que nos está haciendo realmente, si nos fijamos, es que ahora mismo el estado de nuestra aplicación está totalmente separado de React.
No tenemos ningún use state, no tenemos absolutamente nada de React y este estado de aquí que tenemos en realidad lo podríamos reutilizar con cualquier otro proyecto.
Lo podríamos utilizar sin ningún problema porque esto, como hemos visto, lo hemos utilizado en una terminal y nos ha funcionado.
Lo podríamos utilizar con una aplicación de Vue y nos debería funcionar.
Al final, nuestra aplicación, nuestra UI es totalmente agnóstica a la gestión del estado de nuestra aplicación.
Esto es lo que realmente hace que sea interesante este tipo de herramientas y que nos está simplificando un poco cómo lo estamos haciendo.
Es como que tenemos unos pasos, ¿no? Tenemos unos eventos, cuando ocurre este evento, entonces actualizo el estado y ya está. Perfecto.
Hasta aquí esto funciona bien. Una cosa que os recomiendo muchísimo que utilicéis es el tema de utilizar la React Developer Tools.
La React no, la React también la recomiendo. Las Redux DevTools. Yo las tengo ya instaladas, pero son muy potentes.
Y es una de las cosas también por las que cuando tienes una aplicación con mucha lógica, el estado es bastante complejo, es muy interesante utilizar Redux.
Porque tienes las DevTools que te va a ayudar a entender mejor tu aplicación, si tienes algún problema o lo que sea.
Entonces, una vez instaladas, hay que hacer una pequeña cosa. Porque normalmente, al menos en este punto, no funcionaría tal cual.
Aquí se ve que para utilizarla, ¿veis? Hay que añadir esta línea de aquí. ¿Por qué? Porque hay que ejecutar la Redux DevTools cuando creas la Store.
Así que es lo que vamos a hacer aquí. Cuando creamos la Store, ¿veis? Este Create Store. Vamos a añadirla aquí.
Bueno, os voy a enseñar primero cómo aparece el error, para que lo veáis.
Si vamos a seleccionar, quiero que aparece algo así de no está inicializada o algo así. ¿Vale?
No Store found, make sure to follow the instructions. Bueno, pues las instrucciones son estas.
Hay diferentes niveles de hacerlo. Hay algunas veces que se hace automáticamente, sobre todo cuando ya utilizas bibliotecas más grandes.
Pero en este caso, que lo estamos utilizando de una forma muy simple, hay que añadir esta línea y lo vamos a hacer de forma manual.
Cuando se crea la Store, le pasamos un segundo parámetro.
Al final, este parámetro hay que tener en cuenta que solo se ejecutará cuando sea necesario.
Hay que tener cuidado porque esto solo se puede ejecutar en el cliente.
Si es en servidor, esto te petaría. Pero como estamos solo en cliente, no hay problema.
Busca si tienes la extensión y si ya tienes la ejecuta. Eso es básicamente lo que hace.
Ahora, cuando refresquemos, ahora sí. ¿Veis que ahora funcionan perfectamente las DevTools?
Vale, pues cada vez... Aquí. Aquí podemos ver que cada vez que yo ejecute algo aquí...
De hecho, voy a hacer esto responsive y lo voy a hacer aquí, que salga más grande.
Cada vez que yo haga una acción aquí, vamos a verlo en el aspecto.
Si le doy a un más, podemos ver que aquí justamente dice que hay un counter que se ha incrementado.
Si le doy al menos, un counter decremente. Si le doy al reset, counter reset.
Más, más, más, más. Le puedes ir dando que esto lo va valiendo.
Entonces, lo que puedes hacer aquí es ver como un histórico de todos los pasos que has seguido.
Tu aplicación. Puedes ir viendo. Vale, pues esto ha ocurrido en tal punto.
¿Cómo me ha cambiado aquí? ¿Cuál es la diferencia del estado?
Pues ha pasado de este a este de 0, a 1 de 1, a 2 de 1.
Puedes ir viendo justamente cómo el estado ha ido cambiando.
Puedes ver el tip en la acción. Puedes ver toda la información.
Aquí se va añadiendo más información. Ahora mismo solo tenemos el type.
Pero ahora veremos que esto se complica un poco.
Este es el state que ha quedado y esta sería la diferencia.
Es bastante interesante. Además, te puede escribir hasta un test.
O sea, te deja el test justamente para que veas lo que debería hacer.
Y este test te lo puedes copiar y ya lo tendrías. Esto es una maravilla.
Así que es bastante interesante.
Y además, puedes ir hacia atrás en el tiempo.
Ver cómo quedaría tu aplicación cuando estabas así.
Así que os lo recomiendo un montón.
¿Ves? Puedes hacer un jump.
Y entonces dices, voy a saltar a este punto en el que mi aplicación tenía este estado.
Y cuando tenía este estado, pues vamos a ver cuando lo incrementé cómo quedó.
Entonces tú puedes ir saltando y cuando vas saltando, vas viendo aquí cómo quedaba ese estado en cualquier punto.
Te puedes saltar. O sea, es brutal.
La verdad es que en este caso las DevTools de Redux son muy potentes y te ayudan un montón a la hora de depurar una aplicación.
Si tienes algún problema con el estado.