logo

midulive


Transcribed podcasts: 605
Time transcribed: 13d 1h 35m 0s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

En esta clase vas a crear dos proyectos prácticos para que aprendas React de una vez por todas.
Vas a desarrollar el juego del 3 en raya con estado y persistencia de datos en el local storage.
Y una pequeña aplicación donde te voy a explicar con todo lujo de detalles cómo funciona el UseEffect.
Te dejo en la descripción del vídeo un enlace al repositorio donde vas a encontrar todos los vídeos, todas las clases y todo el código de los proyectos.
Y disfruta de la clase.
Nosotros vamos a utilizar VIT para crear nuevos proyectos.
VIT es un empaquetador de aplicaciones web, una alternativa a Webpack muy chula, muy rápida, que está genial.
Entonces, vamos a hacer aquí un npm create bit arroba latest para que utilice la última versión.
Lo ejecutamos, le decimos el nombre de proyecto.
Le voy a poner aquí 02 y aquí podríamos poner nuestro juego, que va a ser el Tic Tac Toy.
Esto es el 3 en raya, no sé cómo lo llamáis en Latinoamérica, si 3 en raya o 3 en línea, no sé.
Pero Tic Tac Toy básicamente es el 3 en raya en España, como lo llamamos de toda la vida.
Vale, aquí le vamos a decir que seleccionamos React y vamos a decirle que lo hacemos con JavaScript más SWC.
SWC es como un babel para compilar el JavaScript, pero mucho más rápido.
En clases posteriores vamos a ver TypeScript, ¿vale?
Y haremos proyectos con TypeScript.
Así que no te preocupes, porque seguro que estás preguntando ya en el chat.
Y vamos a hacerlo con TypeScript, lo haremos más adelante.
Ahora nos vamos a enfocar con JavaScript, a entender React y poco a poco iremos haciendo más cosas, ¿vale?
Así que ahora con JavaScript.
Muy bien, y ahora vamos a 02 Tic Tac Toy, vamos a hacer el npm install que nos está pidiendo por aquí
y levantaremos nuestro proyecto con npm run dev, ¿ok?
Muy bien, npm run dev.
Vamos a tener por aquí el proyecto y ya nos ha levantado aquí en el puerto 5173.
Vamos a hacerlo esto más pequeñito, así que lo vamos a tirar para acá.
Más que nada, para que tengamos juntitos el esto, ¿vale?
Así podemos ver mientras programamos.
Vamos a poder ver lo que vamos haciendo, ¿no?
Vamos al proyecto, al 2.
Ya nos ha creado aquí todos los ficheros, todo el boilerplate que necesitamos para que tengamos una aplicación de React.
Y aquí ya tenemos una aplicación de React con un contador que le podemos dar y empieza a incrementar.
Vale, perfecto.
En el source tenemos el main, que es el punto de entrada de nuestra aplicación.
Este concepto es súper importante y no solo de React, es de la vida en general, ¿vale?
El punto de entrada de nuestra aplicación.
Digamos que es desde donde se construye nuestra aplicación, ¿vale?
Es el primer archivo que se carga para cargar nuestra aplicación.
O sea, esto es lo primero.
A partir de aquí tenemos que ir importando todo el React, ¿vale?
Muy bien, ¿qué más tenemos por aquí?
Bueno, tenemos un componente app.
Aquí podemos ver que tiene un montón de cositas.
Perfecto.
Y este app es el que vamos a eliminar.
Si yo elimino todo esto y pongo return, vamos a poner tic-tac-toe y guardo los cambios, pues ya tengo aquí mi tic-tac-toe.
Ya hemos terminado.
No, no, no, es broma, es broma.
Pero sí que voy a quitar por algo que necesitamos.
Luego lo iremos añadiendo conforme lo necesitamos, ¿vale?
Para que poco a poco pues vayamos increchando, ¿ok?
Oye, muchas gracias por la ride, Matías.
Muchísimas gracias.
Estamos aquí con un curso desde cero de React y vamos a empezar aquí con un proyecto práctico
donde vamos a hacer un 3 en raya, un tic-tac-toe, ¿vale?
Y vamos a ver un montón de cosas interesantes.
Manejar estado, lógica de programación, renderizado condicional, renderizado de listas, eventos y guardar en el local storage.
O sea, vamos a ver un montón de cosas.
Así que quédate que va a estar bien chulo.
Muy bien.
Para empezar nuestro tic-tac-toe, yo creo que lo más interesante primero sería que pudiéramos ver el tablero, ¿no?
Voy a hacer una cosa para que no perdamos tiempo, ni tú ni yo, en el tema de los estilos.
Una cosa que voy a hacer siempre en todos los proyectos es copiarme el CSS y no hacerlo desde cero.
Porque creo que no aporta mucho al curso ahora mismo que hagamos nosotros los estilos desde cero.
Entonces yo todos los estilos o los busco por ahí, de otro proyecto, lo que sea, todos los estilos siempre me los voy a copiar.
Pero no te preocupes porque estos estilos que yo voy a utilizar, ¿ves?
Yo me he copiado estos estilos del tic-tac-toe.
Estos estilos también te los podrás copiar tú o tú los podrás adaptar.
Pero estos estilos los vas a tener en el repositorio de GitHub para que tú también los utilices, ¿vale?
Para que no los tengas que hacer desde cero y te puedas enfocar en aprender React.
No que aprendas React y te tengas que preocupar siempre que los estilos, los estilos y tal.
Entonces he copiado ya todos estos estilos que tenemos una clase board, que es donde vamos a dibujar nuestro board.
Tenemos que asegurarnos que utilizamos bien los classnames.
No te preocupes porque te iré diciendo, oye, aquí tienes que utilizar este, aquí el otro.
Y también tenemos uno turn, que es para decir qué turno es.
Y uno para el ganador, porque vamos a enseñar también como una modal en el que vamos a tener el ganador.
Y luego el square, que digamos que es de nuestro tablero, vamos a tener cada una de las posiciones.
Así que ahí lo vamos.
Muy bien, ¿por dónde empezamos?
Vamos a empezar por el principio, obviamente, ¿no?
Pero lo primero y lo más importante yo creo que es que tengamos en cuenta los turnos que vamos a tener.
Así que voy a crear una constante que vamos a decir, bueno, ¿qué turnos tenemos?
Pues tenemos el de la X, ¿no?
Que en este caso sería X.
Y tenemos el de la O, que en este caso sería una O.
La voy a hacer minúscula, lo puedes hacer como tú quieras, ¿vale?
Luego esto lo puedes cambiar por un símbolo.
Luego lo cambiaremos por un símbolo que queda mejor.
Pero por ahora vamos a empezar con esto.
Tenemos una constante con un objeto, esto ya va a script puro y ya está.
Entonces, ahora ya sabemos que podemos tener turnos, que son o la X o la O.
Muy bien.
Ahora bien, vamos a dibujar nuestro tablero.
Nuestro tablero vamos a tener aquí, vamos a tener que dibujar, vamos a poner board.
Y esto va a ser un board que va a ser un array de nueve posiciones.
Y la vamos a rellenar.
Ahora la puedes rellenar con null.
¿Por qué?
Porque en este tablero lo que rellenaremos después, en realidad, son las X o las O.
Pero ahora mismo lo importante es que tengamos el tablero.
Ya verás que esto lo moveré después para que vayamos viendo qué tenemos que hacer con todo esto, ¿no?
¿Qué hacemos con este tablero?
Pues lo queremos dibujar.
Así que aquí en la app vamos a quitar este H1.
Bueno, más que quitarlo, lo vamos a reutilizar.
Pero vamos a envolver todo este con un main.
Ponemos el class name que tenemos el board.
Vamos a dejar el H1 dentro.
Y aquí vamos a crear nuestro tablero.
Que va a ser una sección que va a tener el class name que le vamos a poner, es el del juego.
Y este class name es porque aquí si buscamos, pues tendríamos, ves, board game.
Y aquí tenemos un display grid donde vamos a utilizar tres columnas.
Van a ser, vamos a decirle, o es una columna de una fracción que se tiene que repetir tres veces.
De esta forma, como tenemos nueve posiciones, lo que va a hacer es a nuevas posiciones las va a distribuir para que nos quede el tablero como queremos.
Vamos a hacer aquí un board, map, y aquí le puedes poner sell, le puedes poner como tú quieras.
Yo voy a poner que vamos a utilizar el índice.
Porque el índice va a ser justamente lo que queremos renderizar.
Vamos a tener la posición 0, la 1, la 2, la 3.
Eso es lo que queremos hacer, ¿vale?
Y aquí, pues tenemos que renderizar algo.
Por ahora, voy a hacer caso a lo que me está diciendo esto.
Para básicamente renderizar algo y que podamos ver ya nuestra pequeña aplicación.
Voy a cerrar este return aquí.
Voy a guardar los cambios.
Bueno, ya ves que al menos ya tenemos las posiciones de nuestro tic-tac toy, ¿no?
El 0, el 1, el 2, 3, 4, 5.
Ahora no debería os mostrar el número porque el número no lo necesitamos, pero bueno, por ahora visualmente ya nos sirve, ¿no?
Muy bien.
Aquí, esta parte del div, vamos a utilizar el concepto de componente que ya vimos en su día, ¿no?
¿Qué es lo que tiene que ser cada parte del tablero?
Pues vamos a tener un cuadrado, que va a ser la posición donde se va a poder jugar cada uno de los movimientos.
Vamos a crear justo encima de la app, vamos a crear aquí un square, que va a ser como el cuadrado del tablero.
Y aquí vamos a utilizar diferentes propiedades.
Vamos a decirle, bueno, el children, que será lo que tiene que tener dentro del tablero, por si queremos mostrar la X o la O.
Vamos a tener también una forma de actualizar el tablero, porque cuando hagamos clic en esa posición tendremos que actualizar el tablero.
Vamos a tener también, vamos a indicar, bueno, vamos a dejar esto, vamos a dejarle el índice, ¿vale?
Vamos a tener el índice para saber ese cuadradito qué índice es.
Y aquí lo que vamos a tener, pues aquí sí vamos a renderizar algo.
Lo que queremos que es renderizar aquí.
En lugar de renderizar este div, renderizaremos squares.
Así que vamos a poner aquí un div con el class name, pero en lugar de cell, yo ya tengo un class name que lo tengo por aquí,
que si lo buscamos es square, ¿vale?
¿Ves el square? Que ya tiene como unos estilos.
Pues vamos a utilizar este square para que mejore visualmente esto.
Y por ahora vamos a poner aquí dentro el children.
Por ahora ya tenemos aquí un componente separado de la app y que ya podemos reutilizar.
Vale, que esto es la clave de React, reutilizar.
Así que este return, ahora en lugar de este div que habíamos puesto por aquí, vamos a hacer algo.
Vamos a poner que aquí queremos utilizar el square.
Y el square, ¿qué necesitamos?
Esto lo vimos, ¿no? Para renderizar una lista de elementos necesitamos utilizar la key.
¿Qué es la key?
La key es un identificador único de ese elemento que renderizamos en una lista.
Las listas de elementos se renderizan con el punto map, porque map devuelve un array.
Así que lo que estamos haciendo es, vale, quiero que cada elemento lo renderices aquí dentro.
Y tengo que identificar cada elemento que renderizo con una key.
Si no, React se me quejará igual.
En este caso vamos a utilizar el index.
Pero si te acuerdas lo que dijimos en la última clase, es que siempre que puedas tienes que utilizar el identificador único.
Y a veces el índice no es un identificador único.
Pero en este caso sí, porque fíjate que aquí 0, 1, 2, 3, 4, 5, estos son únicos.
Nunca vamos a cambiar el índice de esas posiciones.
Así que lo vamos a considerar como que eso.
El propio índice se lo vamos a pasar como prop, porque ya hemos visto que en el square que lo necesitábamos.
También aquí le podríamos pasar más cosas, pero por ahora vamos a pasar.
Ahora bien, hemos dicho que aquí vamos a guardar el índice, ¿no?
Vamos a guardar el índice para ver aquí cómo queda.
Ya empieza a verse un poquito mejor, ¿no?
Ya empieza esto a pillar un poquito de colorcito, ¿no?
Bueno, el tema es que en lugar de los ceros, aquí lo que deberíamos ver en cada uno, fíjate que serían cuando el usuario pulsa para ver si pone los ceros o las x.
Así que vamos a quitar el índice.
No es lo que queremos mostrar.
Pero entonces, ¿qué queremos mostrar aquí?
No queremos mostrar nada, lo dejamos vacío.
Lo cierto es que vamos a necesitar un estado.
Vamos a necesitar un estado para guardar cuando el usuario hace clic en cada posición.
Así que el board que yo lo había puesto aquí fuera, vamos a necesitar meterlo dentro de la aplicación.
Porque cuando en el square se haga un clic, vamos a tener que actualizar el tablero para volver a renderizarlo y que el usuario pueda ver,
oye, si se ha puesto una x o no se ha puesto una x.
Por ahora, vamos a crear, vamos a mover esto que lo había hecho aquí, lo vamos a mover aquí y vamos a pasarlo como si fuese un estado.
Un estado básicamente es un valor que va a, cada vez que cambie, va a volver a renderizar nuestro componente.
Y por lo tanto, cada vez que nuestro tablero cambie, que alguien que tenga su turno cambie un valor en nuestro tablero, queremos que se vuelva a renderizar.
Así que tiene sentido. Y ahora vas a ver un ejemplo mejor que no el hecho de que siempre sea un estado de true o false, como puede ser un interruptor, ¿no?
Que cuando tiene true se ve la luz, cuando false está apagado.
Bueno, también hay estados más complejos, como en este caso un tablero.
Para crear un estado, ¿qué tenemos que hacer? Utilizar el hook uses.
Y aquí le tenemos que pasar el estado inicial de nuestro tablero.
El estado inicial ya lo sabemos, es justamente el que hemos hecho antes.
Y aquí, en lugar de ahora tener una variable, tenemos un array de dos posiciones.
En la primera tendríamos el board y en la siguiente tendríamos una forma de actualizar el board.
Así que ahora ya por lo menos ya tenemos este board, setBoard, y tenemos aquí un array que sería así.
Mira, de hecho puedo poner aquí un console.log del board para que veas cómo tenemos esto.
A ver si lo pone. Ay, no lo pone.
StartConsoleNinja. A ver si funciona el ninja. Vamos a ver.
Porque a veces esto funciona, pero ya veo que este no...
Pause, restart.
Start. A veces me salen aquí en el console.log, pero hay veces que no sé por qué se vuelve tonto.
Bueno, si no, no pasa nada. Os lo puedo enseñar aquí.
Os lo puedo enseñar aquí para que lo veáis, ¿vale?
Pero ahora mismo es una array que tiene todas las posiciones y las tiene nulo.
O sea, porque todavía no estamos jugando.
Pero imagínate que ahora ya podríamos empezar a decir, oye, en lugar de utilizar este, que debería ser el correcto,
imagínate que lo hago a mano, ¿no?
Y pongo, pues aquí tenéis la X, aquí tenéis la X, y aquí tenéis la X, etc.
Mira, vamos a hacer por ahora que sea a mano, ¿no?
Mira, el guisca compadre me había dicho.
Vale, ahora tenemos que asegurarnos que sí que mostramos estos juegos, ¿no?
Aquí, que los podemos mostrar aquí, que ahora mismo no lo estamos mostrando.
Este H1, que este H1, que no tiene aquí espacio.
Vamos a ponerle espacio, ¿vale?
Para que no quede tan juntito.
Margin, bottom, 16, ¿vale?
Ahora, ahora queda así.
Vale, pues vamos a ver que se vea este tablero, que al menos lo veamos visualmente.
¿Qué podemos hacer con esto?
A ver, lo que podemos hacer aquí es acceder al board, acceder al index y, básicamente, mostrar la jugada.
Ya ves que ya empezamos a tener el X, el X, el O, O...
Estos símbolos son un poco raros.
Normalmente, los que se utiliza, y lo podemos cambiar muy fácilmente, sería más bien el de multiplicación, que es este de aquí.
Mira, ¿ves?
Si te fijas, son diferentes.
O sea, te tendría que utilizar el de la derecha.
Pero bueno, después los cambiamos, por ahora los dejamos así.
Aunque se vea un poco feo, luego lo arregla.
Entonces, al menos ahora sí que seríamos capaces de mostrar la jugada.
Pero tenemos que seguir avanzando, ¿no?
Tenemos que empezar a decir, bueno, porque fíjate que aquí tendríamos un ganador.
Y, en cambio, esto habría seguido jugando, ¿no?
Esto también lo tendríamos que arreglar.
¿Cómo hacemos que detecte cuando hemos tenido un ganador?
Pues eso lo vamos a hacer cada vez que el usuario haga clic en uno y actualizamos el tablero.
Lo que vamos a hacer es, vale, voy a ver si ahora ha ganado o no ha ganado.
Pero para que hacer clic actualice el tablero, ¿cómo lo sabemos si no sabemos el turno del jugador?
Así que vamos a tener que ir por partes.
Primero, vamos a necesitar otro estado para saber de quién es el turno.
Si es de la X o del círculo, ¿no?
Primero el turno.
Después, vamos a tener que hacer que esto, en lugar de que empiece así, esté como estaba antes.
Que esté vacío.
Y que cada vez que se hace clic, se rellena.
Así que vamos a hacer eso.
Vamos a volver a poner esto, este estado inicial, como que está todo vacío.
Y vamos a crear un estado para saber de quién es el turno.
Vamos a hacer que empiece el turno la X.
Así que el estado, ¿cómo se hace?
Con useState, le pasamos el valor inicial.
Esto nos devuelve un array de dos posiciones.
Primera posición, el valor del estado.
Segunda posición, cómo actualizar el estado.
Ahora bien, necesitamos también visualmente saber quién tiene el turno.
Porque si no, es muy difícil.
¿Cómo podemos hacerlo?
Pues esto, por suerte, podemos hacerlo en React muy fácilmente.
Porque podemos tener aquí otra sección más.
Section.
Vamos a ponerle class name.
Le vamos a llamar turn.
Porque esto lo tenemos aquí en el CSS.
Y aquí podemos decir que vamos a mostrar un square que tenga el turno.
Vamos a poner aquí turns.
Aquí vamos a mostrar el turno de la X.
Y aquí el turno del círculo.
Pero para que visualmente, ¿ves?
Lo tenemos aquí.
Pero para visualmente saber a quién le toca, vamos a poner aquí una prop.
Que le vamos a llamar isSelect.
Y esto, ¿cuándo vamos a pasarle true al isSelect?
Para saber cuál de las dos está seleccionada.
Y así poder cambiar visualmente cuál es.
Pues vamos a decirle, como tenemos un estado, podemos decir, ah, cuando en este turn tengamos,
cuando el turn sea igual a turns.x, el que va a estar seleccionado es justamente este de aquí, el de la X.
Pero cuando el que esté seleccionado, vamos a copiar esto, cuando esté seleccionado el de la O,
pues vamos a poner este que aquí lo cambiamos por la O.
De esta forma vamos a tener una forma de que el componente square cambie visualmente.
Y esto es súper importante porque esta es la base.
El hecho de poder cambiar visualmente un componente a través del estado de un componente padre.
Lo que está haciendo el componente padre app, es decir, cuando mi estado es uno u otro,
voy a hacer que el componente hijo se vea una forma u otra.
Le va a pasar diferentes parámetros.
Y entonces en el square ahora, podríamos aquí en isSelected, se lo vamos a pasar como prop,
ahora es como le llega.
Y aquí en el class name vamos a decir, va a tener square, pero si isSelected es true,
vamos a tener aquí, vamos a ver cómo se llama aquí, isSelected, ¿vale?
Y así vamos a poder enseñar visualmente si le toca a uno o le toca a otro.
Y este class name lo utilizamos aquí.
Y ya estaríamos haciendo un renderizado condicional, aunque sea solo de a quien le toca el turno.
Así que al menos ya tenemos aquí que ya sabemos que le toca el turno a la X.
Pero cuando le doy click a esto, esto todavía no está funcionando.
Y necesitamos que sí que funcione.
¿Qué podemos hacer aquí?
En el square, que es el componente que hemos hecho para cada uno de los cuadritos,
podríamos pasarle un update board, ¿no?
Y este update board lo que tenemos que hacer es tener una función que le diga lo que tiene que hacer, ¿no?
El update board, ¿qué es lo que tiene que hacer?
Vamos a hacer update board y vamos a crear nuestra función para indicarle cada uno de los pasos que va a hacer nuestra función.
Esta va a ser una de las funciones más importantes, porque es la que se va a encargar tanto de actualizar estados,
de cambiar los turnos, de ver si es el ganador o no es el ganador.
Vamos a poner aquí el update board, ¿vale?
Y lo pasamos.
Fíjate en una cosa, que esto es importante.
En square le pasamos el update board y le pasamos, no la ejecución de la función,
le pasamos la función, para que cuando queramos, desde dentro del square,
se actualice y se ejecute realmente el update board.
Esto es muy importante porque un error muy común es que la gente hace esto.
Y esto sería la ejecución de la función.
No, le estamos pasando la función para ejecutarlo cuando queramos.
Entonces aquí, ¿ves que teníamos el update board?
¿Cuándo tenemos que ejecutar este update board?
Pues le vamos a poner aquí onclick y aquí tendríamos el update board, ¿no?
Y lo podríamos ejecutar aquí.
Pero aquí necesitamos hacer alguna cosita.
Así que por ahora vamos a poner handleclick y vamos a tener update board.
Y por ahora lo vamos a dejar así, ¿vale?
Y este vamos a poner aquí el handleclick.
Y esto luego lo actualizamos.
Luego vemos qué tenemos que hacer aquí.
Pero por ahora lo importante es que cuando el usuario haga clic en el div,
vamos a tener un onclick que llama el handleclick, que llama el update board.
Por ahora lo dejamos así.
Luego veremos si tenemos que pasarle alguna información o qué tenemos que hacer.
Por ahora eso lo hacemos.
Vamos a volver al update board, que lo tenemos por aquí.
¿Ves?
Que tenemos nuestra función vacía.
¿Qué es lo que le va a llegar al update board?
Al update board por ahora no le va a llegar nada.
Pero bueno, aquí podríamos pasarle cosas.
Luego veremos qué le podemos...
¿Qué podemos hacer aquí?
Bueno, aquí me dicen cosas que podría hacer.
Más o menos necesitamos hacer algo así.
Pero bueno, por ahora vamos a ver.
Primero, vamos a cambiar el turno para asegurarnos que podemos cambiar un turno entre uno y otro.
Así que vamos a tener el nuevo turno, lo tenemos que calcular con lo que tenemos actualmente.
Y si el turno es igual al de las X, significa que el nuevo turno va a ser el de los círculos.
Y si no, va a ser el de las X.
Aquí lo que estamos haciendo, como no podemos hacer un cambio de booleano, ¿sabes?
No le podemos pasar de true a false.
Lo que estamos haciendo aquí es decirle, oye, si el turno es de las X, el nuevo turno va a ser el del siguiente.
O sea, el del círculo.
Y si es del círculo, será el de las X.
Eso es lo que estamos haciendo, ¿vale?
El chat está en modo lento, pero mido está espídico.
No me jodas.
Bueno, pero ¿qué pasa?
No entendí por qué se pasa la función y no la ejecución.
Buena pregunta.
Es súper importante esto, porque yo no quiero ejecutar la función.
Si yo ejecuto aquí la función, vamos a hacerlo.
Vamos a hacerlo, ¿vale?
Vamos a hacerlo para que lo veas.
Mira, console.log update.board.
Para que veas que esta función, cuando se ejecuta, que es lo que...
Tú imagínate que le pasas la ejecución de la función, claro.
Y tú renderizas esto.
Si tú vas a...
Mira, se ha ejecutado la función nueve veces.
¿Tú quieres ejecutar la función nueve veces porque se ha renderizado la square?
No.
Tú no quieres ejecutar la función hasta que el usuario no haga clic.
Si tú le pasas la ejecución de la función, estarías rompiéndolo.
Porque lo que estás haciendo es...
No, no.
Ejecuta esta función.
Y esa función puede estar haciendo setStates.
O sea, estarías...
Cada vez que se renderiza, estarías actualizando el board.
No tiene sentido.
Tú lo que quieres es ejecutarlo solo cuando lo necesitas.
Solo cuando se hace clic, ¿vale?
No cuando se renderiza.
Esa sería la diferencia, ¿vale?
Y súper importante.
Y esto es un error que muchas veces la gente dice,
¿pero por qué no la ejecución?
Bueno, porque la ejecución la querrás hacer cuando quieras, ¿no?
No cuando se renderiza.
Y esa es la diferencia.
Entonces, queremos controlar realmente cuando...
Vale, vamos a dejar como estaba.
Entonces, queremos que la ejecución se haga cuando se haga clic.
Entonces, por eso se la pasamos como parámetro a nuestro square.
¿Vale?
El square es cada uno de estas posiciones en el board.
¿Ok?
Ok.
Vale.
Entonces, aquí tenemos el new turn.
Pero ya sabéis que para poder actualizar el estado, lo que tenemos que hacer es llamar al setTurn.
Así que vamos a hacer setTurn y le pasamos el nuevo valor que tiene el turn.
Por ahora, tenemos esto, ¿no?
Cada vez que vamos a hacer clic en cada uno de los cuadrados, vamos a cambiar el turn.
¿Vale?
Pues fíjate.
Bueno, no sé si te puedes fijar porque estoy encima.
Pero bueno, dejadme arreglar eso en un momento.
Vamos a ver para que no aparezca yo arriba.
Vamos a poner esto aquí.
File.
Esto sí.
Items start.
Ahora no me acuerdo.
Items start.
Bueno, si quitamos este y este.
Mejor, ¿no?
Y así lo vemos arriba y así no tiene ningún problema, ¿vale?
Así lo tenemos mejor.
Pues fíjate que ahora, cuando le voy dando aquí a cada uno, ahora al menos ya estamos cambiando el turno.
¿Cómo estamos haciendo esto?
Vale, vamos a volver a tirar del hilo para ver un poquito de esto, ¿no?
Lo que estamos haciendo es, estamos renderizando cada uno de los squares dentro del tablero.
Cada square tenemos aquí el índice y tenemos el update board.
Y el update board, se lo estamos pasando como prop al componente.
El componente square lo que dice es, bueno, cuando alguien haga clic en el div, o sea, en este div,
este div que tenemos aquí entre todo lo que está dentro de este borde, pues lo que va a hacer es ejecutar la función handleClick.
La función handleClick ejecuta la función updateBoard que le estamos pasando desde arriba, ¿vale?
Y esta función updateBoard es la misma función que estamos ejecutando aquí.
O sea, esta función la que le estamos pasando como parámetro y esta función en la que tenemos aquí es la que ejecutaremos aquí.
Si tú aquí le pasas un parámetro, este parámetro va a ser el que le va a llegar aquí, ¿vale?
Así que esto es lo que estamos haciendo.
Desde el componente padre app le pasamos la función updateBoard y esta función updateBoard la ejecutamos solo cuando hacemos clic en el div, ¿ok?
O sea, que es súper importante que estemos haciendo el, estemos pasándole la función, no la ejecución, ¿vale?
¿Por qué usas una variable newTorn y no haces el setState negando turn?
Hostia, Idant, esa es bastante, bastante tela, ¿eh?
A ver, vamos a ver, turn no es true o false, es x o o, es x o o, claro, no es true o false, ¿vale?
O sea, que no se puede negar y ya está.
También yo creo que es mucho más legible si hacemos esto, que no utilizamos que esto sea true y que esto sea false.
Yo creo que es mucho, mucho, mucho más legible.
Entonces así lo evitamos.
No es un booleano, un string que en realidad estamos utilizando como un enum, ¿vale?
Así que eso.
Y turn, sí, el turn es del turno, ¿eh?
Estos son los turnos, no es de prender.
Estos son de los turnos, ¿vale?
Pues ya al menos tenemos una forma de ir cambiando el turno.
Pero obviamente en el updateBoard tenemos que hacer más cosas, ¿no?
Cuando actualizamos el board tenemos que hacer más cosas.
Cuando el usuario hace clic, le vamos a pasar el índice para saber en cuál de estas ha hecho clic.
De esta forma decimos, vale, ha hecho clic en la 0, en la 1, en la 2, en la 3, en la 4, en la 5, en la 6, en la 7 o en la 8.
Y así vamos a poder actualizar el board con esa información.
Vamos a decir, vale, vamos a ver.
Vamos a tener que decirle, vamos a tener un nuevo board y vamos a poner que el nuevo board, como recibe el índice, vamos a ponerle el valor del turno actual.
Y así, el usuario que ha dado clic, que tenía turno, le ha dado clic a esa posición, en esa posición ha guardado ese, puede ser aquí, X, U, O.
Una de las dos, ¿no?
Así que al menos con esto ya tendríamos el board.
Obviamente todavía tenemos que actualizarlo.
¿Cómo lo hacemos?
SetBoard, NewBoard.
Ya está.
Con estas tres líneas vamos a actualizar ya que el board se actualice, o sea, que se vea visualmente.
Vamos a ver, ¿vale?
Pues ya tenemos al menos, o sea, ya tenemos el juego.
Ya casi tenemos el juego.
Bueno, como ves, hay una cosa que no está bien.
Uno, el juego no termina nunca.
Dos, puedes sobreescribir donde estás haciendo clic.
Obviamente son cosas que tenemos que mejorar, ¿no?
Pero ya tenemos lo que sería todo lo que es la actualización del estado en que se ve visualmente, ¿no?
Que si le doy aquí a la X, aquí a acá, tan, tan.
Necesitamos que el usuario gane, o sea, saber cuándo gana.
Y además necesitamos que, si lo he completado todo, que termine el juego, que pare ahí.
Pero al menos en este ratito ya tenemos todo esto, todo esto hecho.
Ahora, antes de continuar, primera pregunta.
¿Por qué hago esto?
¿Por qué he hecho una copia del board?
¿Por qué no hago esto?
¿Por qué no hago esto?
Y ya está, ¿no?
Y aquí le pongo el board.
¿Por qué no hago esto?
Ya os pongo la X.
¿Por qué esto está mal?
Está mal, ¿vale?
Esto está mal.
Hacer esto, hacer esto, está mal.
¿Por qué está mal?
Porque no tenéis que mutar nunca las props ni el estado.
Tenéis que tratarlo como si fuesen inmutables.
Esto quiere decir que los arrays no tenéis que modificar el valor que tiene, sino que tenéis que hacer es siempre crear un nuevo array con el valor.
¿Y esto cómo lo podéis hacer?
Podéis hacerlo, en este caso, con un spread operator.
¿No?
Aquí podéis decir, bueno, pues del board quiero que todos los elementos que están dentro del board me los metas en un nuevo array.
Por eso es súper importante, y yo os decía en la primera clase, que saber entender el spread y el rest operator es súper importante, ya no solo en React, en JavaScript en general.
Si no sabes esto, cuando termines esta clase, te pones a estudiar esto, porque significa que te queda mucho.
Y sin esto es imposible que luego pases cualquier probator.
Así que esto lo tienes que aprender.
Súper importante.
Puedes hacer una copia de un array de forma superficial, que esto también es importante, con esto.
Para hacerla de forma profunda, si fuese necesario, podrías utilizar StructureClone.
En este caso no lo necesitamos y por eso no lo vamos a utilizar.
Pero al menos podríamos hacer una copia profunda del array así.
No lo necesitamos, pero solo para que lo...
Entonces, los estados siempre hay que tratarlos como inmutables.
Entonces tú me dirás, ostras, ¿pero por qué?
¿Por qué hay que hacerlo como inmutable?
Porque si tú lo mutas, si tú lo que haces es modificar el estado, lo que puede ocurrir es que haya problemas de renderizado.
Porque tú has modificado el estado directamente en lugar de utilizar el setboard.
Lo que estás haciendo es modificar el estado actual sin llamar al setboard.
Y lo que puedes tener son discrepancias en el renderizado.
Por eso es importante que los datos siempre sean nuevos.
Los datos del nuevo renderizado siempre sean nuevos.
Siempre hay que pasarle un array nuevo.
Siempre hay que pasarle un objeto nuevo.
Siempre tiene que ser algo nuevo.
O el mismo.
Si es el mismo no pasa nada.
Pero si lo han modificado tiene que ser uno nuevo.
Así que por eso estamos haciendo la copia.
Muy importante.
Súper importante.
Y esto ahora sí que está bien.
Hemos hecho la copia para evitar modificar el original.
Importante.
Fino.
Bueno, pues ya tenemos aquí esto.
Ahora, ¿qué podemos hacer?
¿Qué podemos hacer para evitar que se sobreescriba?
Porque ya ves que se sobreescribe.
A ver, lo primero que podríamos hacer es que cuando vamos a actualizar el board, voy a decir, oye, si en el board, en el índice hay algo, pues oye, no escribas, ¿no?
No actualizamos esta posición si ya tiene algo.
Como por defecto son nul todas las posiciones.
Claro, si tú intentas actualizar la posición, aquí miras, oye, la posición tiene algo, pues return, ¿vale?
O sea, no hace nada.
Ahora, al menos, vamos a ver que cuando yo intento hacer clic encima de una posición que ya hay algo, no me deja.
Es sencillo, pero efectivo.
Y ahora lo demás sí que funciona, pero ya no me deja hacer clic en ningún sitio.
O sea, ya sería una forma de decir, oye, hasta aquí, hasta aquí.
Esto ha terminado, hasta aquí.
Bueno, ya tenemos lo del nuevo board.
Esto sería actualizar el tablero.
Vamos a decir aquí que esto es cambiar el turno.
Pero necesitamos dos cosas, ¿no?
Una, saber cuándo hemos ganado.
Por ejemplo, si yo hago esto, significa que ha ganado la X.
Tendríamos que parar el juego aquí.
Tenemos que decir, oye, ha parado el juego.
¿Cómo podemos hacer esto también?
Con un estado.
Podemos saber cuándo tenemos un ganador utilizando un estado.
Así que lo que vamos a hacer aquí es crear un nuevo estado que nos diga winner, set winner, use state null, ¿vale?
Vamos a decir que el null es que no hay ganador y el false es que hay un empate, ¿vale?
Vamos a utilizar el null como que no hay ganador y el false un empate.
Esto lo podéis hacer de otra forma.
Por ejemplo, en winner podríais utilizar también un enum como hemos hecho con los turnos.
Pero lo vamos a hacer así por simplificarlo.
Pero luego la idea es que muevan las manitas.
O sea que esto al final yo lo dejo así, pero lo importante es que lo entiendas y a partir de aquí tú hazlo como tú quieras.
Hay muchas formas de ver cuál es el ganador en el 3 en raya.
Y esto es importante para la lógica de programación, que muchas veces la gente me pregunta, ¿cómo practicar la lógica de programación?
Bueno, pues aquí tienes un ejercicio de lógica de programación mucho más interesante que hacer un ejercicio por ahí suelto.
Mucho más interesante hacer un juego que normalmente tiene mucha lógica de programación que no hacer un ejercicio suelto.
Y mira que a mí el App Engine me encanta, pero es mucho mejor hacer esto porque al final ves la gracia de la lógica.
Una forma muy fácil, y yo creo que no solo fácil, sino a veces recomendada, pero no del todo la más óptima, sería tener todas las combinaciones ganadoras.
O sea, podríamos tener una constante que le vamos a llamar combos, o winner combos, y podríamos tener un array donde tenemos todas las combinaciones ganadoras.
Por ejemplo, la línea, si tienes el 0, el 1 y el 2, el 3, el 4 y el 5, el 6, el 7 y el 8.
Entonces esas son combinaciones ganadoras, ¿no?
Por lo tanto, aquí deberíamos poner el 0, 1 y el 2, el 3, 4 y 5, 6, 7 y 8.
Luego también tendríamos las verticales, o sea, tendríamos el 0, 4, 7, ¿no?
Pues bueno, ahí las tenemos.
El 0, 3, 6.
A ver, 0, 1, 2, 3, 6.
Vale, 0, 3, 6.
Perdón.
Menos mal que dije, compañero, las ha hecho bien.
1, 4, 7 y 2, 5, 8.
Estas serían las verticales, pero también nos faltan las diagonales, que serían 0, 4, 8, 2, 4, 6 y ya está.
No teníamos más.
Estas serían, 0, 4, 8 sería esta, esta y esta.
Mira, te la puedo hacer, puedo hacer.
Esta sería una.
Y la otra sería hacia el otro.
Esta sería otra.
Estas son todas las combinaciones ganadoras.
Hay otras formas de hacerlas, muchas más óptimas, que te invito a que lo practiques.
El hecho de cómo puedes saber el ganador, la ganadora, rápidamente, haciendo el mínimo número de combinaciones.
Pero bueno, nosotros lo vamos a hacer así, porque es bastante fácil de hacerlo.
Y podríamos tener aquí un método que le vamos a llamar CheckWinner, que recibe un board, como el board, como el tablero para chequear.
Y aquí, pues podemos decir, vale, para cada combinación que tenemos en los winner combos, estos, vamos a hacer una cosa.
Vamos a mirar.
Vamos a...
Muy bien, joder, qué bueno que jacopilot.
Vamos a recuperar las posiciones A, B y C. O sea, vamos a recuperar 0, el 1 y el 2.
Y lo que voy a hacer es, primero voy a mirar si el board to check en la posición A existe algo, ¿no?
Pero luego voy a mirar si en la posición A y en la B es la misma.
O sea, ¿qué estaría mirando, por ejemplo?
Primero voy a mirar si en el 0 hay un número.
Luego voy a mirar si...
O un número no, si hay una X, ¿no?
Si hay una X, por ejemplo.
Una X o una O.
Y luego voy a mirar si en el 0 y en el 3 está exactamente la X y luego la X o la O y luego la O.
O sea, si tienen lo mismo.
Y lo mismo ya para el tercero, ¿no?
Que sería el A igual a C.
Bueno, esto lo podemos hacer de diferentes formas, pero esta sería una, ¿no?
Si la A es igual a la B y la A es igual a la C, significa que tenemos un 3A.
O sea, que tenemos ya un ganador.
Así que vamos a devolver quién es el ganador.
Y el ganador sería el que está justamente en el primer elemento.
En este elemento, esto nos debería devolver X o O.
Una de las dos.
Y ya sabremos con esto fácilmente cuál es.
Si no tenemos ganador, bueno, pues no pasa nada.
Aquí, en el for, vamos a decir que esto nos devuelva a null, que no tenemos ganador, ¿no?
Si no hay ganador, pues ya.
Con esto revisamos todas las combinaciones ganadoras, ganadoras, para ver si X o U ganó, ¿vale?
Y ya está.
Con esto ya podemos chequear si tenemos un ganador.
¿Y cuándo tenemos que chequear si tenemos un ganador?
Lo tenemos que chequear siempre, lo tenemos que hacer, ¿cuándo lo tenemos que hacer?
Bueno, pues chequear si tenemos un ganador lo podemos hacer cuando actualizamos el board, por ejemplo.
O sea, cuando estamos haciendo todo esto, podríamos decir, bueno, pues aquí vamos a revisar si hay un ganador.
Vamos a ver si ahí tenemos, vamos a ver si tenemos un new winner.
Utilizamos el check winner, le pasamos el nuevo tablero que hemos creado aquí, porque tenemos que ver el nuevo tablero que tiene el último movimiento, no vamos a utilizar el antiguo, ¿vale?
Si tenemos un nuevo ganador, bueno, esto significa que tenemos que hacer un set winner y ya está, tenemos un new winner, punto, ya está.
Ahora, vamos a ver si tenemos ganador, si no tenemos ganador y qué hacemos con este ganador.
Cuando hemos actualizado nuestro componente con el ganador, tenemos que renderizarlo también, porque si no, no vamos a verlo.
Y vamos a seguir jugando y tal y esto no tiene sentido.
De hecho, cuando tenemos un ganador, también tenemos que evitar que se pueda seguir actualizando el board.
O sea que, no solo cuando el board intentemos hacer clic en la misma, sino que si tenemos un ganador, ¿no?
Si aquí board no sé qué o tenemos un ganador, pues entonces no funciona seguir jugando, porque estaría, no tendría sentido.
Tenemos un ganador y seguimos jugando, no tiene sentido.
Así que por eso, cuando en esa posición del tablero ya hay una ficha o tenemos un ganador, pues si tú haces clic, no funciona.
Ahora, vamos a ver si al menos paramos de jugar.
Yo hago aquí esto, ¿vale?
Vale, ya no me funcionan los clics porque ha detectado que tengo un ganador, pero visualmente no estamos viendo quién ha ganado.
Tenemos que informarle al usuario, oye, ha ganado Pepito, ha ganado quien sea.
Podríamos hacerlo con un alert, ¿no?
Podríamos decirle, oye, aquí un alert, alert, mira, ganó, el ganador es...
Bueno, esto sería un poco pirata, ¿no?
Pero bueno, al menos sabemos que ha ganado la X, ¿ves? Y se muestra aquí, ha ganado la X.
Fíjate, esto es interesante, ¿no?
Fíjate que cuando lo he hecho así, fíjate que sale el alert antes de que se vea visualmente.
¿Sabes por qué pasa esto?
Esto pasa porque he puesto el alert antes del setWinner.
Pero si lo pongo después, ¿va a salir la X o no?
Pregúntatelo.
Piensa en ello.
¿Va a salir la X o no?
¿Va a salir la X o no?
No sale tampoco.
¿Por qué cuando pongo el alert justo después del setWinner visualmente no se ve la X?
¿Qué significa esto?
¿Qué significa esto?
Esto es súper importante en React y lo tienes que tener aquí a fuego, ¿vale?
Con lo que te voy a decir ahora mismo.
La actualización de los estados en React son asíncronos.
Esto quiere decir que esto no es síncrono.
Esto no bloquea.
No bloquea el renderizado.
Y entonces de repente, de repente vas a ver aquí, vas a ver aquí que ya tienes en Winner el nuevo valor, ¿no?
Como esto actualiza el estado, actualiza el estado, la actualización del estado es asíncrono.
Esto quiere decir que puede ocurrir en 100 milisegundos, 250, pero no bloquea la ejecución del código que viene justo después.
Y esto es muy importante no solo por esto que estamos viendo visual, sino porque si yo pongo un console.log de Winner, aquí, ¿vale?
Si yo pongo aquí un console.log de Winner, hay gente que si esto fuese síncrono, si esto fuese síncrono, que no lo es, si fuese síncrono, aquí en el console.log de Winner, que estamos leyendo el estado, aquí alguien podría pensar que Winner tiene el estado nuevo y no lo tiene porque es asíncrono.
Así que esto tenlo muy en cuenta. En la actualización del estado es asíncrono.
Y aquí puedes tener el nuevo valor o no lo puedes tener. No puedes contar con ello, ¿vale?
De hecho, vamos a verlo. Si yo pongo un ganador, ¿ves? Me sale null justo después de actualizarlo.
Porque claro, como esto es asíncrono, aquí no tiene todavía el nuevo estado, ¿vale? Esto es súper importante.
Lo tenéis hasta aquí, esto lo habéis entendido bien, porque esto es súper importante, ¿vale?
Esto es un algo que hay mucha gente, hay mucha gente que todavía con años de experiencia falla en esto.
Y esa es una de las razones por las que fíjate que aquí en el Check Winner no le estoy pasando el nuevo board.
Porque si yo le pasase, si no le pasase el parámetro y en Check Winner, y en Check Winner, en lugar del board to check,
utilizase el del estado, tendríamos un problema. Este es un error muy común, muy común.
Y esto es básico, es básico, pero no sé si es que los cursos no lo explican, no lo sé.
Pero esto es básico. Si no sabes esto, no entiendes. O sea, no entiendes el estado, no sabes cómo...
Si yo en el board, en el Check Winner, le utilizase el estado, claro, alguien podría pensar que aquí en board ya tiene el estado nuevo.
Pero el problema es que no lo tiene. No lo tiene porque como esta actualización es asíncrona,
pues no podemos fiarnos que el Check Winner va a poder ver el valor que...
Así que tenemos que asegurarnos... Mira, vais a ver el error. Vamos a verlo y vais a ver que tiene un error.
Vais a ver que esto falla. Si yo ahora hago esto, pam, pam, pam, pam, pam, pam, ojo,
me ha dejado jugar, pero ya no me deja jugar. ¿Por qué ha pasado esto? Me ha dejado hacer una jugada más
pese a que había ganado ya. Y eso es porque el Check Winner ha funcionado con el valor del estado anterior.
Y tenemos que asegurarnos que utiliza el nuevo. La forma de solucionarlo ya la hemos hecho.
Es muy sencilla. Es que nos aseguramos de que le estamos pasando el valor que necesita.
Ya está. Esta sería una forma, ¿no? El hecho de decir, oye, por parámetro, cosa que a mí parece una buena práctica en general
para asegurarte que estás utilizando el valor correcto, ¿vale?
Lo ves, queremos el New Board, pues le ponemos aquí el New Board o el Board to Check, ¿vale?
Esto es un error muy común porque la gente tira el estado como suena mañana.
Esto sería una forma de arreglarlo. Y tendríamos otra forma de arreglarlo todavía.
No en este caso, aunque sí que lo podríamos hacer. O sea, podríamos hacerlo,
pero os voy a explicar un caso de arreglarlo en el Set Winner.
El Set State, o sea, cuando actualizamos el estado, podemos pasarle un nuevo valor o le podemos pasar un Call.
Le podemos pasar una función. Y la función que tenemos aquí, lo que tenemos que devolver aquí,
tenemos que devolver el New Winner. O sea, este sería el valor que queremos que actualice.
Y aquí como parámetro le llega el Previous Winner. Esto, en este caso, aquí no lo necesitamos.
No lo necesitamos porque no sirve para nada. Es opcional porque el Previous Winner aquí no lo necesitamos.
Pero si quisiéramos, podríamos verlo. Podríamos decir, console.log. Vamos a poner el ganador es el New Winner.
El anterior era Previous Winner. Y esto sería una forma de poder acceder al estado anterior y al nuevo estado al que tú quieras tener aquí.
Pero no puedes, igualmente esto, como puedes ver aquí, esto es asíncrono.
Igualmente esto te asegura que dentro puedes tener acceso al New Winner, porque eso lo vas a pasar tú, porque tú sabes lo que tienes que hacer.
Vas a poder tener acceso al anterior, por si quieres hacer cualquier tipo de comparación entre el anterior y el nuevo.
Pero ten en cuenta que esto igualmente es totalmente así, ¿vale? O sea, que esto no asegura que...
O sea, lo que pasa es que aquí puedes ejecutar lo que tú quieras. Ya está. Con el valor anterior.
Pero no puedes pasarle un callback de decir... No puedes hacer una sync await, ¿sabes?
No puedes decirle... No puedes hacer algo así. No puedes hacer aquí una wait. No funciona, porque no devuelve una promesa.
No puedes hacer eso. Punto pelota, ¿vale? Ahí lo tendríamos, ¿vale?
Pero el Previous Winner no sería un ganador válido, ¿no? Hombre, sería nul. Válido es porque nul es nul, ¿no?
O sea, no pasa nada. O sea, sería nul, no pasa nada. Vale.
Os voy a subir mientras, porque a lo mejor alguien lo está intentando hacer a la vez.
Os voy a subirlo... Bueno, os voy a subir todo por ahora.
Voy a subir Start Team Second Project, ¿ok? Y sincronizamos los calles. Muy bien.
Entonces, hemos avanzado. Ya tenemos nuestro juego. Pero fíjate, un juego es un ejercicio maravilloso.
Porque poco a poco te vas dando cuenta de los problemillas que van apareciendo.
Y hacer que todo funcione como esperamos es bastante interesante.
Pero bueno, lo importante es que ya tenemos el New Winner. En este caso ya lo tenemos todo bien.
Tenemos el ganador, todo parece que funciona bien.
Pero cuando... Si no tenemos un ganador... Bueno, podría intentar aquí a ver si no la lío.
Si no tenemos un ganador... A ver... Otra vez no. Otra vez no. Otra vez no.
A ver, aquí no soy capaz de hacer que no se han ganado. Joder. Vale. Vamos a hacerlo.
Eh... Aquí esto... Vamos a dejar aquí... Este aquí... A ver si es que... ¿Cómo la lío?
Este lo dejamos aquí... La lío, ¿eh? Vale.
Pues fíjate que el juego en realidad ha terminado, pero no puedo seguir jugando básicamente porque...
Porque he hecho la lógica de que si ya tiene una cosa... O sea, si ya tiene una X, una O, no puedas ponerla.
Pero realmente no sabemos si hemos empatado, si ya ha terminado el juego. No lo hemos notificado.
Y esto también lo vamos a tener que hacer. Así que nos faltaría aquí... Vamos a poner aquí...
Check if game is over. ¿Vale? Lo vamos aquí. Vamos a poner el to do para hacerlo después.
Nos faltaría esto. Por ahora vamos a hacer... Mostrar si tenemos un ganador. ¿Vale?
Vamos a decirle... Oye... Si hay un ganador, vamos a hacer algo.
Para eso, tenemos aquí una sección para el juego. Tenemos una sección para los turnos.
Y ahora vamos a hacer una sección... Vamos a hacer una sección con un renderizado condicional.
De forma que si winner es diferente a null, porque null es por defecto, o sea, no tenemos winner.
Vamos a hacer algo. Si es diferente a null, significa que puede ser false, puede ser X o puede ser círculo.
Vamos a renderizar algo. Vamos a poner un section, class name. Vamos a ponerle winner.
Este estado es una modal... Este class name es una modal que tengo por aquí. ¿Vale? ¿Ves?
Winner lo tengo aquí. Esto nos va a dibujar una modal. Y en esta modal vamos a poner con un div.
Vamos a tener aquí el texto. Y aquí tenemos que decir quién ha ganado.
¿Quién de los dos ha ganado? Bueno, pues vamos a ver.
En el caso de que el winner sea false, vamos a decir que ha habido un empate.
Pero si no, vamos a decir quién ha ganado. Y el que ha ganado, vamos a decir, ganó más winner, ¿no?
Para ver la X y A y tal. Pero voy a hacerlo un poquito más bonito.
En este caso, voy a hacer que el que ganó muestre también, como en el turno que hemos hecho esto, que también lo muestre.
Y así, pues hombre, quedará un poquito más bonito porque si a alguien le interesa ver y quiere empezar a mejorar.
Así que vamos a poner un header aquí. Vamos a poner aquí que el win, que si tenemos un winner, vamos a poner aquí square.
Y dentro le ponemos el win. Así lo dibujamos dentro de una square y queda más bonito, ¿no?
Y vamos a poner por aquí un footer. Por ahora lo vamos a dejar vacío.
Bueno, vamos a poner el botón ya para hacerlo después. Que sea empezar de nuevo.
Bueno, porque nos gustará volver a empezar. ¿Ves? Aquí tenemos ya. Ganó la X.
Porque la X había hecho esto aquí. Ah, es que en realidad ganó la X. La madre que me parió.
No es que había terminado, es que ganó la X. Bueno, vamos a ver. Vamos a ver.
Antes había ganado la X y yo diciendo, no, he hecho que no funcione. Vale, ahora sí.
¿Ves? Ahora no ha ganado ninguno. Ahora no ha ganado ninguno. Vale.
Aquí es donde deberíamos decir, si ha terminado, pues hacemos set winner a false.
Ahora vamos a hacer que gane la X. ¿Ves?
Ahora sí tenemos en la modal que nos dice, ha ganado la X.
Si hacemos que gane la Y, debería también aparecernos, ¿no?
Aquí, este aquí. Ganó. Este.
O sea, ya tenemos la lógica de cuál de los dos ha ganado.
Tenemos aquí empezar de nuevo. Este es súper fácil.
Normalmente en los juegos, o no tanto en los juegos, sino en cualquier aplicación de React en la que quieras empezar de nuevo,
vamos a poner reset game, ¿no?
Vamos a hacer que cuando se clique, se ejecute la función reset game.
Lo que tenía que hacer la función reset name game, igual que lo tendría que hacer en cualquier aplicación,
por ejemplo, para resetear un formulario, para resetear lo que sea,
lo único que tenemos que hacer es asegurarnos que seteamos el estado a sus valores iniciales.
O sea, si aquí teníamos array nuevo fill null,
que empiece el turno la X y que el winner es null,
pues exactamente eso es lo que tenemos que hacer.
El board, pues array nueve fill null.
El turno, turno X, set winner null.
Y esto automáticamente ya, lo que va a pasar cuando hagamos clic en esto, es que empieza otra vez.
Y esto es una de las grandes maravillas que tiene React.
El hecho de que nuestra UI es replicable, se replica.
Lo importante es que le pasemos las mismas procs y que tengamos el mismo estado.
Y esto lo que hace es que nuestra interfaz se replique.
Y este concepto lo puedes llevar no solo a un juego.
Es que en cualquier página web esto te va a pasar.
Filtros de búsqueda, un formulario.
Formulario, si te gusta o no te gusta algo, si has empezado a escribir un texto,
lo que sea que se te ocurra, esto es tan fácil como volver a resetear con el estado que quieres.
Punto pelota, punto pelota.
Ya está.
Ves, tú vas jugando, pam, pam, pam, dices X.
Empezar de nuevo y empieza de nuevo.
Tan sencillo como esto.
Porque hemos reseteado directamente el estado.
No hemos tenido que resetear la página para hacer esto,
que muchas veces eso va a ser innecesario y una mala práctica,
porque a lo mejor hay estados que sí que nos interesa guardar.
Claro, si tú actualizas la página,
primero es que tienes que cargar todos los recursos de nuevo
y luego que hay estados que a lo mejor sí que te interesan.
Esto puede ser parte de una aplicación mucho más grande
en la que solo quieres que se resetee el estado de este componente.
O sea que no es lo mismo hacer un location.reload que resetear.
Vamos a poner aquí en el tic-tac-toe, vamos a poner aquí también otro botón,
que sea justamente esto, reset del juego.
Y vamos a hacer aquí el on-click con reset, había puesto reset game, ¿no?
Reset.
Y así vamos a tener también un botón fuera, aquí, para poder hacer un reset del juego.
Reseteamos.
Nos faltan todavía dos cositas.
Empieza, está bastante cerca ya de...
Ya pintaba todo bastante bien.
Y yo creo que lo que es de visualizar, de qué tenemos que renderizar, lo tenemos bien.
Nos faltan dos detalles.
Uno, que cuando empezamos el juego, si yo reseteo, se pierden los cambios.
Que esto lo vamos a hacer con local storage y yo creo que es muy interesante
para que vean lo fácil que es también.
Y lo segundo, que también nos falta, es el hecho de que si no gana nadie,
que veamos que es un empate, ¿no?
Y cómo podemos hacer esto, ¿no?
Vale, para lo del empate, ya había dicho aquí, check if game is over.
Es muy fácil, muy fácil ver si realmente hay un empate.
Y el juego va a terminar.
¿Cómo lo vamos a hacer?
Vamos a hacer aquí, if new winner set winner, ¿vale?
Y si no, else if.
Vamos a ver si...
Bueno, es que es esto básicamente casi.
Pero lo que vamos a hacer aquí es hacer un check end game.
Y le vamos a pasar el new.
Y si tenemos esto, pues vamos a poner set winner false.
Si chequeamos el juego, si chequeamos el juego y no tenemos ningún ganador, ¿no?
Hacer check end game.
Si chequeamos el tablero, vemos que se han dicho todos los movimientos posibles.
No vemos ningún ganador.
Hacemos set winner false.
Y esto significa que ha habido un empate.
Ha terminado el juego y tenemos un empate.
Vamos a hacer este check end game.
Check end game.
Le pasamos el new board.
Y esto es súper fácil de ver si...
Mira, revisamos el empate si no hay más espacios vacíos en el tablero.
Efectivamente.
Es así de fácil.
Para revisar esto, como si te acuerdas el tablero, el new board era un tablero que era así, ¿no?
New, null, null, null.
Y nosotros vamos poniendo x, o, x.
O sea, vamos como en cada posición vamos poniendo nuevos valores.
¿Qué pasa?
Que una vez que todas las posiciones que tenemos en el tablero, todas las posiciones, sean diferente a null, significa que se han hecho todos los movimientos.
Y por lo tanto, ya ha terminado el juego y ha terminado como empate.
Para hacer eso, utilizamos el new board, utilizamos el every.
Decimos, si todas las squares, si todas las posiciones del array new board, todas, tiene que el square es diferente a null, esto significa que será x o y.
Pues el square x o y significa, pues nada, que ha terminado el juego.
Por lo tanto, esto devolverá true.
Chequeamos si ha terminado el juego.
Si todos son diferentes a null, pues significa que ha terminado el juego.
Y con esto, ya lo tendré.
Ahora, si soy capaz, si soy capaz de...
Mira que tengo tela, ¿eh?
A ver, si soy capaz.
A ver, ¿lo he conseguido?
Muy bien, empate.
Bueno, pues ya tenemos el empate.
Ya tenemos el empate.
Güey, me ha costado, ¿eh?
Me ha costado más el tema del empate que hacer el programita.
Bueno, pues ya tenemos aquí el empate y ya, pues empezar de nuevo.
Y ya tendríamos nuestro juego.
Con esto, hemos hecho toda, toda la lógica, toda la lógica de un 3 en raya.
Y lo hemos hecho, pues nada, aquí en vivo, en directo, en una horita.
En una horita, mientras lo estaba explicando, ¿vale?
Ahora, a partir de aquí, podéis hacer lo que queráis.
En una pregunta, el board.map, board.map.
Esto, esto es la primera posición.
La primera posición sería el square, o sea, lo que hay en ese square.
Esto, realmente, podríamos hacer esto así.
Ya está.
Entonces, debería ser exactamente lo mismo.
Yo le había puesto esto porque al principio no lo estamos usando, pero ya está.
¿Queremos confeti para celebrar?
Claro, podemos hacer...
Ahora vamos a arreglar algunas cosas.
Vamos a hacer lo de guardar la partida, que es súper interesante guardar la partida, ¿vale?
También lo vamos a hacer.
Guardar la partida.
Podríamos hacer lo del confeti, si queréis.
Eso es súper fácil.
Vamos a...
Mira, vamos a hacer lo del confeti.
Canvas, confeti.
Vamos a añadir una dependencia para que cuando terminemos,
hacemos el confeti, ¿vale?
Vamos a import, confeti, from, canvas, confeti.
Y vamos a hacer que si hay un winner, set winner, ta, ta, ta.
Winner, si hay un ganador, aquí, set new winner.
Vamos a hacer el confeti y ya.
Y así, cuando tengamos un ganador, echamos un confeti.
En un momentito, ¿eh?
En un momentito.
¿Habéis visto?
En un momento.
O sea, con esto hemos hecho que saque el confeti en el caso de que tengamos un...
Pero, bueno, son estos detalles que son súper sencillos y que, pues, bueno, le da subidita, ¿no?
Vale, cosas...
Esto habría que mejorarlo, ¿no?
Primero, vamos a separar los componentes.
Por ejemplo, aquí tenemos el square.
El square, para sacarlo en un fichero aparte, podríamos crear aquí components
y podríamos tener aquí square.jsx.
En lugar de tenerlo aquí, vamos a sacarlo y lo vamos a poner aquí.
Para sacarlo, ponemos también aquí export.cont.square.
Y para utilizarlo aquí, hacemos un import de square from components.square.js.
Esto lo ponemos aquí y ya lo tenemos.
Luego, también podríamos crear un fichero que sea constantes.
Constants.js.
Y entonces, en lugar de tener aquí estas constantes, podríamos sacarlas.
Y la vamos a sacar aquí.
Tenemos aquí el export.
Y así, allá donde queremos utilizar estas constantes, que tienen bastante sentido en nuestra aplicación,
las podremos importar fácilmente.
Tenemos el de dos turnos.
Tenemos el winner.
Con esto ya tenemos más cositas que hemos sacado.
¿Qué más podríamos hacer?
En realidad, hay cosas que podríamos sacar incluso de la parte del componente.
Fíjate que este check winner, si lo quisiéramos testear, es muy interesante porque no necesitamos
nada visual aquí.
Aquí lo que tenemos es justamente un check winner que le pasas un board y hace este check
a través del winner combos, pero ya está.
O sea, que esto también lo podrías llegar a sacar.
Lo puedes sacar en un utis, lo puedes sacar donde tú quieras.
Igual podríamos tener también la carpeta logic, donde tengamos aquí board.js y aquí
pues vamos a tener check winner.
Exportamos el check winner.
El check winner.
Tenemos que importar el winner combos y el check winner.
Check winner from.
Vamos a poner from para que quede bien con el board, no sé qué.
Si no hay ganador.
Y esto lo podemos ya quitar de aquí.
Vamos a esto de aquí.
Importamos el import check winner from.
Y el check winner ponemos este.
Ahora ya empezamos a utilizar menos cositas aquí.
¿Qué más podríamos hacer?
Podríamos hacer más componentes.
Que como podéis ver aquí, pues no hemos hecho...
Los componentes que hemos hecho es un poco regular, ¿no?
Por ejemplo, toda la parte del winner, toda esta parte en realidad, la podríamos...
Toda esta la podríamos extraer.
Muy fácil.
Esta es la gracia de React, ¿no?
Componentizar.
Crear el winner.jsx.
Vamos a poner winner modal, ¿vale?
Porque tiene sentido que sea modal.
Y esta parte fácilmente nos vamos a nuestra aplicación.
Y esta parte quitamos...
Mira, esto es interesante, ¿no?
Hay veces que esto lo queremos dejar fuera o lo podemos dejar dentro.
En este caso lo vamos a dejar dentro para que quede todavía más fácil, ¿no?
Vamos a poner aquí el winner modal, que ahora mismo todavía no lo estamos exportando.
Export con...
Bueno, function winner modal.
Return.
Vale.
Y aquí fácilmente vamos a ver lo que necesitamos.
Fíjate que aquí empezamos con un renderizado condicional.
Lo que podemos hacer aquí es mejor decir, oye, si el winner es null, ya directamente me devuelves null.
Y esto ya lo vamos a dejar para salir de la función antes.
Va a quedar mucho más claro, va a ser mucho más fácil de leer.
Ay, espérate.
Aquí se me ha escapado esto, que he hecho una mezcla, ¿vale?
Fíjate que con esto lo que estamos consiguiendo es, oye, si no tengo winner, devuélveme null.
Punto.
Ya está.
Más rápido.
Y esto me lo deja bastante más limpio.
Porque así no tenemos que ver, yo que sé, si no estamos anidando mucho.
Es mucho más fácil de leer.
Aquí vamos a poner winner text, ¿no?
Y el winner text pues también lo podemos dejar aquí.
Así de esta forma esto lo podemos dejar mucho más limpio, ¿vale?
Esto es ya como buenas prácticas.
A mí me gusta mucho dejar la parte del renderizado lo más limpia posible.
Y también vamos a poder ver qué es lo que necesitamos para que esto funcione.
Obviamente necesitamos, por un lado, necesitamos el winner, necesitamos también el reset game
y necesitamos también, creo que ya está, ¿no?
El reset game, el winner y ya está, ¿verdad?
Y entonces, como hemos hecho un export function y no un export default function,
cuando importemos, vamos a importar de forma nombrada, winner modal, componentes estos
y ya empezamos a componentizar nuestra interfaz.
Le tenemos que pasar el reset game, game y el winner.
Y esto es algo que tendríamos que empezar a ir repitiendo constantemente
y ver cuáles son las oportunidades que podemos ir separando, ¿vale?
Ya vemos que por ahora parece que todo funciona bien.
No he roto nada, ¿vale?
Ah, mira, me he cargado el winner modal por algo.
Algo he hecho ahí que no le ha...
Square es... Ah, no he importado el square, ¿vale?
Este square, este de aquí, no le importa nada.
Lo he importado.
Square, con esto, ahora sí, ahora sí.
Ya lo tengo.
Pero en un momento, o sea, no hemos tardado absolutamente nada,
no hemos tardado absolutamente nada en cómo componentizarlo.
Obviamente, desde el principio tenemos que haber hecho así, ¿no?
Pero esto, la idea también era que pudieras ver cómo lo vamos haciendo paso a paso,
que lo puedas acompañar muy fácilmente y que luego veas cómo tienes que utilizar React
para todo lo que pueda ser reutilizable, lo puedas componentizar.
No de que metas todo en un componente y tal, sino que lo puedas componentizar, ¿vale?
Y aquí, por lo mismo, mira, este check in game, también esto sería parte de la lógica del board, export const.
Lo bueno de esto es que este check in game, como no tiene nada de...
Si lo puedes pasar por parámetro, tiene más sentido que lo separes directamente.
Porque piensa que esta lógica, ahora, esta lógica, la puedes usar en un componente de React,
en uno de Angular, en uno de Vue, en uno de Svelte, porque todos son JavaScript.
Entonces, esa es una de las grandes maravillas que tenemos.
El hecho de poder separar lógica, que es JavaScript puro, y directamente hacerlo
que sea totalmente agnóstico al lenguaje o a la biblioteca que estamos utilizando de interfaz.
Esto es una muy buena práctica, muchas veces se nos pasa,
y dejamos nuestros componentes de React llenos de cosas que realmente podrían estar fuera,
y que el día de mañana, si tú quieres hacer este mismo juego, el Tic Tac Toe,
en otro, en Solid X, en Svelte, lo que sea, todo esto lo vas a poder reutilizar.
Porque es la misma lógica.
Así que eso es súper importante y estas cosas son las que marca el Live.
Vale, entonces, este Check in Game, ya hemos visto que ahora,
vamos a sacar aquí del Game, y bueno, podríamos sacar más cosas, ¿no?
Por ejemplo, generar un nuevo turno, todas estas cosas también se podrían llegar a hacer.
Pero bueno, yo creo que por ahora, esto también, el tablero, lo podrías sacar en un componente.
Este trabajo, este ejercicio, ya os lo dejo a todos ustedes, a vosotros.
Porque creo que es muy interesante el hecho de que vayáis viendo cómo, pues no sé, mejorar visualmente.
Podéis incluso hacer que esto sea multiplayer.
No es muy difícil con lo que hemos hecho, igual, mira, más adelante igual lo haces.
También os había dicho que íbamos a utilizar algo más bonito, porque es verdad, veis esta X y esta O.
No os quería mezclaros al principio, pero fijaos lo bonito que es esto.
Que ahora, con todo lo que hemos hecho, si cambiamos esto aquí, solo cambiando esto aquí, con los símbolos bonitos, ¿vale?
En lugar de la X y la O utilizar los símbolos que le pertoca, si guardamos los cambios, fíjate que ya, vale, lo que le falta, porque veo...
Ah, no, ya está. O sea, ya con esto, ya con esto, tenemos, ya con esto, solo con este cambio.
O sea, tú aquí le podrías poner lo que quieras, y automáticamente, ya en toda tu aplicación,
como hemos utilizado un enum, aquí podéis ver justamente la potencia de tener una constante y utilizar un enum.
¿Por qué? Solo cambiando aquí estos dos strings, visualmente nuestra página cambia totalmente.
Y fíjate que ahora las X que estamos utilizando son mucho más bonitas, ¿vale?
Así que fíjate, en un momento lo hemos hecho también. Ahí lo tenéis, ahí lo tenéis, ¿vale?
Símbolos bonitos, ahí todo. Podríais utilizar emojis si queréis, claro, también podéis utilizar emojis.
Y además que son de colores, o sea que circle, a ver si hay un circle, no sé si utilizaré, ya...
¡Ay! Espérate, eso es que... Pero ya está, lo tendríais así, en un momento.
Pim pam, pim pam, en un momentito. Podéis utilizar emojis, podéis utilizar lo que queráis, ¿vale?
Lo que queráis. Vale, os voy a subir estos cambios.
¡Ah! Nos queda una cosa muy interesante, que es la de guardar la partida, ¿vale?
Vamos a poner, vamos a ver, vamos a ver. Extract to components tic-tac-toe.
Vamos a poner, vale. Vamos a hacer una cosa muy fácil para que entiendas la potencia del estado en React también.
Vale, cuando nosotros estamos jugando, si yo reseteo, pierdo los cambios.
Tiene sentido también, o sea, tiene sentido porque, claro, no hemos hecho nada para que no los pierda.
¿Qué podemos hacer para asegurarnos que cada vez que actualizamos, si tenemos una partida a medias, pues podamos seguir jugando, ¿no?
O sea, que digamos, oye, no quiero perder los cambios, yo lo que quiero es tener aquí mis cambios de la partida que tenía.
Bueno, lo que vamos a hacer es que cada vez que haya un movimiento, vamos a hacer en Update Board, cuando hacemos un movimiento, vamos a hacer una cosa.
¿Dónde deberíamos guardarlo? A ver, podríamos guardar todo el estado cuando tenemos un ganador y tal, pero bueno, yo voy a hacer antes de saber si tenemos un ganador.
O sea, vamos a hacerlo justamente antes. O sea, lo vamos a hacer aquí.
¿Por qué? Vamos a dejar siempre que se quede en el último movimiento, por si acaso.
Vamos a guardar aquí partida, ¿no? ¿Por qué? Porque tengo el nuevo turno, tengo el board.
¿Cómo vamos a hacer esto? Con el local esto. Vamos a llamar local storage, hacemos setItem y le decimos que vamos a guardar el estado del tablero.
Importante, en local storage lo que puedes guardar es un string.
Por lo tanto, si tú intentas guardar directamente el array, lo que te va a guardar no es lo que.
Lo que te va a guardar, y lo podemos ver, es otra, ¿vale?
Tú puedes guardar esto, intentas guardar un array, y sí, te ha guardado algo, pero no...
¡Oh, ojo! Vale, no es lo que... ¿Vale? ¿Ves que me lo ha guardado así?
Esto es porque ha llamado al método toString automáticamente.
Y tú cuando en un array llamas al método toString...
Ah, no sé si tú llamas al toString, ¿ves? Te lo convierte directamente en esto.
Te hace un join con la... Esto no lo que... Así que fuera.
Esto es lo que queremos. Lo que queremos es que nos guarde un string y lo vamos a guardar el stringify.
Vamos a llamar del JSON stringify para que el array nos lo convierta en un string, pero después lo podamos volver a transformar.
Y esto mismo lo vamos a hacer con el turno, para saber quién le tocaba el turno, o no vamos a volver la partida y que el turno se resetee.
Así que vamos a guardar estos dos aquí. Guardamos aquí la parte.
Ahora, ¿qué tenemos que hacer para saber que tenemos que leer esto?
Bueno, cuando inicializamos el estado, fíjate que estamos haciendo aquí array 9.fill.
No podemos... Y os voy a explicar una cosa. Está prohibido esto. O sea, no podéis hacer leer aquí en local storage, ¿no?
Y entonces aquí utilizarlo así. Esto no está bien. Tampoco está bien hacer esto.
Si tengo desde local stage, entonces voy a poner el estado aquí, así. Si no, lo hago. Esto tampoco.
El useState, todos los hooks nunca jamás pueden estar dentro de un if. Esto es súper importante.
¿Por qué? ¿Por qué es esto? Porque React guarda la posición de cada useState en un array interno en memoria y dice,
primero se ejecuta este, luego se ejecuta este, luego se ejecuta este. ¿Qué pasa si lo pones en un if?
Pues que pierde las posiciones. Dice, ostras, pero si primero se ejecutaba este, ¿por qué ahora se ejecuta este?
Entonces los useStates siempre, siempre tienen que estar en el cuerpo de tu componente.
No puede estar dentro ni de un if, ni de un while, ni de un loop, ni de nada. Tienen que estar en el cuerpo de la forma.
Y la forma correcta que tenemos de leer el local storage y inicializar el estado, dependiendo si tenemos local storage o no,
es que en lugar de pasarle directamente el valor, le podamos pasar aquí, le podemos pasar una función.
Y aquí lo que sí que podemos hacer es, oye, voy a recuperar el board from storage.
Y esto vamos a hacer windowLockerStorage.getItem. Y entonces vamos a devolver que si tengo board from storage,
vamos a hacer un json.parse de lo que tenía en el storage para que esto sea con lo que inicializamos el estado.
Esto sería el valor inicial de nuestro estado. Y si no, utilizamos el valor por defecto que tenemos, ¿vale?
Esto lo podéis hacer de otra forma. Si no os gusta las ternarias o nada, podéis hacerlo con un if.
Si tengo from storage, hago un return del json.parse.boardFrom. Y si no, devuelvo el array 9 fill null.
Total, como arriba hemos puesto un return, como aquí hemos puesto un return, no ejecutará esta línea.
Cualquiera de las dos funciona sin problemas, ¿vale? Cualquiera de las dos.
¿Por qué esto lo hacemos dentro de esta función? Esto es súper importante y también mucha gente no lo sabe.
Vamos a poner aquí un console.log y le voy a llamar inicializar esta.
Y vamos a poner aquí un console.log que le vamos a llamar render.
Inicialista, estado del board, le vamos a llamar, para que lo vea aquí.
Vale, inicial. Bueno, ahora aquí alguna cosa me he petado. Vamos a ver que me he cargado.
Ah, it's not valid. Ah, hostia, es que he guardado. Es porque he guardado en el local storage lo que...
Window, local storage, he guardado lo que no deberíamos haber guardado.
Remove item board, para empezar de cero. Vale, ahora.
Entonces, ahora tengo esto, refresco y fíjate que se ha quedado esto.
Si miramos la consola, vamos a ver, render, inicializar estado del board. Vale, render, inicializar estado del board.
Si yo me pongo, render, render. O sea, cada vez que se renderiza, ejecutamos este console.
¿Qué significa? ¿Por qué es importante esto? Porque si tú pones este local storage get item, lo pones fuera, se va a ejecutar, se va a ejecutar esto de aquí, en cada render.
La línea 11 se va a ejecutar en cada render de forma innecesaria. Y esto es lento.
El leer del local storage es muy lento. Es súper lento, es síncrono y bloquea.
Por lo tanto, vamos a intentar evitar que en cada render vuelva a leer el local storage cuando no lo necesita.
Si tú haces esto, si tú haces esto en cada render, vaya a leer el local storage.
Entonces, ya sabemos que podemos inicializar el estado pasándole el valor directamente, pero en este caso, como queremos que la inicialización, porque ya sabéis, la inicialización solo ocurre una vez.
Pues podemos pasarle una función que solo se va a ejecutar una vez, porque la inicialización del estado solo ocurre una vez.
Y entonces, dentro, vamos a leer el local storage. Así nos evitamos que nuestros componentes sean más lentos.
Hacemos aquí una vez y ya. Así que vamos a seguir la misma técnica, la vamos a seguir con los turnos.
Vamos a decirle, bueno, vamos a tener aquí turn from storage, window cal storage.
En este caso, como directamente es un string, ningún problema. Podríamos hacer return turn from storage y si no, turns.exe.
Si tengo algo form, no, from. Si tengo algo desde el storage, utilizo el de storage.
Si es null o undefined, utilizo el por defecto que es turns.exe.
Todavía nos falta una cosita más, un detallito, ¿no? Porque claro, si yo lo doy al reset del juego y refresco, ves que me ha vuelto a guardar lo que tenía el local storage.
Tenemos que asegurarnos que cuando reseteamos el juego, también reseteamos lo que tenemos en el local storage.
Así que vamos al local storage, remove item, board, y también lo mismo lo hacemos con el turn. Y ya está.
Ahora, cuando reseteamos el juego, si refrescamos, vemos que sí que se...
Y si jugamos y lo dejamos por lo que sea, medias, y refrescamos, pues vuelve a estar aquí nuestra partida preparada para que empecemos, ¿vale?
Así que ya tenemos aquí nuestro primer jueguecito con el tic-tac-toe, con todo el tema de arriba.
Preguntas que tenga la gente, mis amigos, ¿qué tal? ¿Qué preguntas?
Nicolás dice... ¡Fuah, Nicolás! He explicado esto tantas veces, Nicolás. De hecho, es que lo expliqué ayer.
Que si esto y esto es lo mismo. No son lo mismo, obviamente, ¿no?
Esto... ¡Ah, sí! Falta guardar el... Ahora lo arreglo.
Esto, mira si esto es falsi. Y esto, mira si esto es null o undefined. ¿Vale?
Vale, el turno se me ha olvidado porque... ¡Ah, no! Pues el turno aquí está bien.
GetItemTurn, turno X, si lo tenemos de storage... Pues no sé, ¿dónde se nos ha quedado?
Hola, aquí estamos, ¿qué tal?
Y si quiere que el usuario elija el contenido de los cuadros, pues también lo podrías hacer, pero bueno, habría que hacer más cosas.
Lo podríamos hacer, pero habría que hacer más cosas y tenemos que explicar algo.
El turno no ha funcionado bien. Puede ser... A ver, vamos a ver.
El turno no ha funcionado bien. Vamos a ver aquí el GetItemTurn.
¿Cuándo...? ¡Ah! Es que aquí... Es que aquí esto... Tenemos que guardar el nuevo turno.
He guardado el anterior. ¿Vale? Ahora ya. ¿Ves? Ahora sí. Ahora sí.
¿Ves? Estoy refrescando, refresco y ahora sí que se queda bien.
Aquí me había equivocado y estaba guardando el anterior y no el correcto. ¿Vale?
Ahora sí que está funcionando. ¿Vale? Mira, y empate.
Empezar de nuevo. Refrescamos. Ahora sí.
Midu, siempre que tenemos que cortar una función para que no siga ejecutando código,
si al cumplir la condición quiere devolver un alert.
¿Está mal hacer un return alert?
¿Un alert? Pregunto esto porque muchas veces escuché que el return se utiliza para recuperar un dato específico
y no tanto va a ejecutar algo como un alert o un console.log.
A ver, el alert es que bloquea.
Yo no os recomiendo que utilicéis nunca alert, a no ser que sea para probar algo,
porque lo que vais a encontraros es que el alert bloquea la ejecución del código.
Yo no os lo recomiendo.
Si quieres hacer un multiplayer, pues a ver, puedes utilizar una base de datos.
Es que esto que hemos hecho en local storage, esto lo podríamos hacer en otro sitio.
Vaya, no me sabía lo del estado asíncrono. Pues es bastante importante.
Hay otra forma de guardar estado al recargar la página o siempre se usa así.
En este caso, hemos utilizado local storage. Lo podríamos guardar en una base de datos.
Podríamos pedir esto a la base de datos otra vez en el use effect, lo vamos a ver ahora también.
¿Podrías explicar la diferencia entre spread y el rest? Hoy no, porque estamos ahora con React y creo que ahora no.
Puedes limpiar local storage.clean. Es una práctica regular, Javier.
Porque, a ver, en este caso sí que funcionaría, lo tenemos muy controlado,
pero yo creo que es buena práctica que borréis específicamente lo que queréis,
porque si no vais a borrar demasiadas cosas.
¿Puedes mover el getItem afuera del componente en este caso?
Claro que sí. Podría... Esto, por ejemplo, podríamos guardar aquí en logic.
Podríamos tener storage. Podríamos tener aquí un index.s.
Podríamos hacer export const save game.
Y aquí le podríamos pasar la información que queremos guardar, ¿no?
Por ejemplo, queremos guardar tanto el board como el turno, ¿no?
Esto lo puedes tener fuera. Lo sacas de aquí, pam, pam.
Y también port game storage, reset game.
Y esto, pues, window.local storage.
Esto, el game. Y así, pues, podéis empezar a hacer esto y sacarlo de ahí.
¿Que el día de mañana lo hacéis en otro sitio?
Bueno, pues, aquí podéis empezar a hacer las mismas llamadas.
Y esto, pues, lo importáis.
Import save game storage, reset game storage.
Y entonces, en el reset game storage, esto aquí, esto aquí.
Y aquí, guardar la partida, save game to storage.
Tendríamos el board.
El board, que sería el JSON stringify del new board.
El JSON stringify incluso lo podéis hacer dentro.
O sea, que vamos a hacerlo.
Creo que tiene más sentido lo vamos a hacer dentro,
para que no tenga que el componente preocuparse de tener que hacer eso.
Pues, si el día de mañana queréis hacer esto, board, turn.
Y ya hemos hecho aquí, pues, otra cosa, ¿no?
Tenemos ahora, pues, un save game to storage, reset game storage.
Y lo tenemos aquí.
Y esto debería funcionar exactamente igual.
Y funciona.
Bueno, ahora la he liado otra vez, porque...
Ah, ¿ves? Otra vez.
El turn, este que habíamos puesto aquí, otra vez está mal,
porque le tengo que pasar el new turn.
Pero ya está, con esto ahora, ya lo hemos refactorizado en un momento, ¿vale?
Ya lo tendríamos.
Lo del estado síncrono es muy frecuente.
A mí me sucedió que un formulario me quedaba siempre el último carácter pendiente.
Hoy veremos lo de Zustan.
No, eso lo veremos más adelante.
Me refiero a hacer el gateintent antes de montar el componente, afuera.
No, no tiene...
Lo podrías hacer, pero no tiene sentido.
Tiene sentido que lo hagas justamente al inicializar el estado.
Midu.
Con lo cual, siempre que se tenga algo de lugar a estar,
se ha de poner dentro del estado y jamás fuera del estado.
A ver, a ver.
Hay que tener una en cuenta de una cosa.
Ahora mismo estamos ejecutando React solo en el cliente.
Entonces, vamos a quedarnos con el scope de lo que estamos haciendo ahora.
No podéis, si ejecutáis React, los componentes de React en el servidor,
no podéis acceder a window.localStorage.
Y por lo tanto, lo que hemos hecho no funcionaría en el servidor.
Pero más adelante veremos si está en el localStorage y tenemos servidor,
cómo tenemos que recuperarlo correctamente.
¿Vale?
Pero hay que tener en cuenta.
Esto es porque ahora solo estamos ejecutando en el cliente.
¿Vale?
¿Hacer un ajedrez cuándo?
Pues dale cañita.
O sea, cuando tú quieras.
Mueve las manos.
¿Dónde entra aquí el useEffect?
Todavía no entra a ningún sitio.
¿Cómo se llama el programa?
¿Dónde haces eso?
Visual Studio Code.
¿Podrías explicar de nuevo los callbacks dentro del useState, por favor?
Ostras, el callback dentro del useState básicamente es una función
que tiene que devolver el valor con el que quieres inicializar el estado.
¿Vale?
El año pasado hice un Conecta4.
Claro, es que con lo que hemos hecho hoy,
ya podéis empezar a hacer un Conecta4,
podéis empezar a hacer un montón de cosas.
No conocía a bit.
¿Qué diferencia hay de Creative Recap?
Que uno está hecho con Webpack, otro con bit,
y que bit funciona bastante.
Y un montón de diferencias más que obviamente no nos da tiempo a explicar aquí.
¿Vale?
¿Podrías explicar la lógica del juego?
La he explicado antes, o really.
Hemos explicado la lógica.
Tenemos una constante que nos dice todas las combinaciones ganadoras,
y lo único que hacemos es recorrer, recorrer.
Hemos creado aquí...
Lo que hacemos es recorrer esta constante con todas las combinaciones ganadoras,
y si hay algún elemento que está repetido en esas tres posiciones,
pues nada, lo que hacemos es decir que hay ganadorias.
¿Podrías explicar la ventaja de usar una función y tener lógica dentro del state?
Es que las hemos explicado también, amigo.
Es que no puedo explicar todo el rato lo que acabamos de explicar,
porque es que si no, nunca avanzamos.
Explicar por qué dentro la lógica del state.
Es que ya lo acabo de explicar, y es una explicación bastante larga,
que ahora es muy complicado que te la pueda volver a resumir.
Pero es que ya he dicho que la iniciación del estado solo ocurre una vez,
y tiene sentido que la hagamos.
Lo que te recomiendo es que te vuelvas a mirar el vídeo,
porque ahí verás que lo hemos...
Vale, vamos con el useEffect.
¿Vale?
Vamos a darle con el useEffect,
para que tengamos el siguiente,
y ahí además vamos a estar practicando otras cositas.
¿Vale?
Hasta ahora hemos visto un hook, que es el useState.
El useState nos permite tener un estado en nuestro componente,
un estado que al cambiar vuelve a renderizar nuestro componente
para reflejar en la interfaz los cambios.
Y el useState es súper importante,
pero en React hay un montón de hook.
Y cada hook, digamos que tiene un objetivo distinto,
que nos va a permitir hacer que nuestra aplicación
se comporte de forma diferente.
Y el segundo hook más importante que tiene React es useEffect.
¿Qué es lo que hace useEffect?
Bueno, simplemente, y esto, grábatelo.
UseEffect es un hook que nos permite ejecutar código arbitrario
cuando el componente se monta en el DOM,
y cada vez que cambian las dependencias que nosotros le digamos.
Eso es lo que es useEffect.
Luego puedes tener explicaciones más grandes,
pero esa es la explicación corta y ligera de lo que es el hook useEffect.
Un hook que nos permite ejecutar código arbitrario
cuando se monta el componente y cada vez que las dependencias,
y ahora verás lo que son las dependencias,
cómo funcionan las dependencias, no te preocupes,
las dependencias que nosotros le digamos cada vez que cambien,
le digamos, oye, cuando esto cambie,
quiero que vuelvas a ejecutar este código.
Eso es lo que sería un useEffect.
¿Cómo es el hook useEffect?
Antes vamos a hacer un proyecto práctico
para que lo veas muy claro
y vamos a ver algunos problemas que nos vamos a ir encontrando
con el hook useEffect,
para que veas cómo funciona, qué problemas puedes tener.
Pero lo más importante, digamos, que es su contrato,
para que lo veamos.
Imagínate que tenemos aquí un componente.
Ahora pongo la pantalla, que no la he puesto.
Vale, vamos a poner la pantalla.
Imagínate, ¿qué es código arbitrario?
Código arbitrario quiere decir el código que a ti te dé la gana.
Eso es lo que significa código arbitrario.
Arbitrario es porque es el código que tú quieras, ¿sabes?
Es el código que te dé la gana.
O sea, no es un código que está establecido por RIA,
que es el código que tú quieras,
el que a ti te dé la gana.
Vale, entonces, imagínate que tenemos un componente.
Ya hemos visto que para crear un estado
tenemos que llamar useState, ¿no?
Y lo importamos.
Y el useState, pues tendríamos el valor inicial
y aquí tendríamos el valor
y la forma de actualizar el valor del state.
Esto sería el useState.
El primer hook que hemos visto.
¿Cómo es el contrato del useEffect?
El useEffect se utiliza en el cuerpo
de nuestro componente, de esta forma.
Y tenemos que importarlo igual que el useState de RIA.
Lo importaríamos así.
Y aquí, esto, el hook, como todos los hooks,
son funciones.
Y esta función recibe dos parámetros.
Uno, que sería el código para ejecutar,
codeToExecute, execute.
Y aquí tendríamos la lista, listOfDependencies.
¿Vale?
Serían estos dos parámetros.
Así que el codeToExecute, ya sabemos
que va a ser una función.
Aquí tendríamos una función.
Y aquí, el código, el código a ejecutar.
¿Vale?
Ya sabemos que como mínimo, esto, como mínimo, como mínimo,
se ejecutará una vez.
Como mínimo, siempre el useEffect se va a ejecutar una vez.
¿Por qué?
Porque cuando se monta nuestro componente,
se ejecuta una vez.
¿Vale?
Ahora bien, ¿se puede ejecutar más veces?
Se puede ejecutar más.
En la lista de dependencias, aquí lo que se le tiene que pasar
es una red.
Pero ojo, este segundo parámetro es opcional.
Quiere decir que puedes no pasárselo.
Y si no se lo pasas, lo que quiere decir es que este código
se va a ejecutar no una vez.
Se va a ejecutar cada vez que se renderice el componente.
Y esto será la primera vez, la segunda, la tercera,
cada vez que se renderice el componente,
esto se va a ejecutar.
Esto de aquí dentro.
Entonces, veremos que en el console.log vamos a tener
el código a ejecutar.
El código a ejecutar.
O sea, esto se va a ejecutar cada vez que se renderice
nuestro componente.
Y esto lo podemos ver de forma muy sencilla.
Porque si vamos otra vez a nuestro proyecto que acabamos de hacer,
por ejemplo, este del tic-tac-toe,
vamos a poner aquí un useEffect simple y sencillo.
Vamos a poner un useEffect.
Vamos a traernos el useEffect.
Y vamos a hacer aquí useEffect.
Voy a poner el useEffect.
¿Dónde hemos dicho que tenía el useEffect?
En el cuerpo, ¿no?
Y aquí tenemos que ponerle el código que queremos ejecutar.
Aquí vamos a poner useEffect.
No le vamos a pasar el segundo parámetro por ahora,
que tendría que ser un array, pero es opcional.
Por lo tanto, este useEffect debería ejecutarse
cada vez que se renderiza nuestro componente.
Bueno, pues vamos a levantar aquí.
Vamos a reiniciar.
Bueno, claro, es que tiene la partida guardada.
Vamos a reiniciar.
Voy a inspeccionar.
Y vamos.
Vale, ya veis que el useEffect se ha ejecutado dos veces.
Bueno, vamos a jugar.
A ver qué pasa.
Le doy aquí una vez.
Se ha ejecutado otra vez.
UseEffect.
Otra vez.
UseEffect.
UseEffect.
¿Por qué pasa esto?
Porque cada vez que actualizamos el estado,
esto renderiza otra vez nuestro componente.
Y como se vuelve a renderizar nuestro componente,
como este useEffect, le hemos dicho,
que no tiene ninguna dependencia de nada,
esto lo que hace es que se está ejecutando
cada vez que se renderiza nuestro componente.
Cada vez que se renderiza nuestro componente,
lo tenemos aquí.
Luego te explicaré por qué,
nada más reiniciar, tenemos dos y no uno.
Deberíamos tener solo uno, pero tenemos dos.
Luego te explico por qué pasa esto.
Pero lo importante que tenés en cuenta ahora
es que cada vez que se renderiza nuestro componente,
puedes ver que tenemos un nuevo useEffect.
Ahora bien, imagínate que tú solo quieres ejecutar el efecto una vez.
O sea, solo quieres ejecutar código
cuando se monta por primera vez el componente.
¿Cómo lo podemos hacer?
Aquí irían las dependencias.
Estos son valores que nosotros queremos decir,
cada vez que cambie este valor,
quiero ejecutar este código de aquí.
Como mínimo, se ejecuta una vez,
como hemos visto, ¿no?
Cuando se monta el componente.
Vale, si le pasamos un array vacío,
lo que va a hacer nuestro useEffect
es ejecutar solo cuando se renderiza por primera vez el componente.
¿Qué quiere decir esto?
Pues que por más veces, ¿ves?
Lo tenemos dos veces.
Luego te explico por qué,
nada más entrar aparece dos veces,
no te preocupes.
Es una tontería, muy fácil de entender.
Pero imagínate que aquí solo sale una vez.
Ahora, por más que yo estoy volviendo a renderizar,
como le he dicho,
que oye, no te tienes que fijar en ninguna cosa,
no hay ninguna dependencia,
simplemente solo cuando te renderiza por primera vez,
pues ahí es cuando tienes que render.
Por eso vemos que esto no vuelve a ejecutarse el efecto.
¿Ok?
Pero como vamos a ver más adelante,
aquí podríamos ponerle una lista de dependencias.
Por ejemplo, quiero que te ejecutes cada vez que ha cambiado el turno.
O quiero que te ejecutes cada vez que cambia el board.
O cada vez que cambia el board o el turno.
O cada vez que cambia cuando hay un ganador.
De esta forma, este efecto se va a ejecutar.
Ahora ya sabemos que se va a ejecutar.
El useEffect se ejecuta la primera vez que se renderiza
y cuando cambie el winner.
Y lo podemos ver fácilmente.
Si vamos aquí, ¿ves?
Se ha ejecutado por primera vez.
Si yo me empiezo a jugar,
y ahora le doy aquí,
otra vez se ha ejecutado el useEffect.
Porque le hemos dicho,
oye, ten en cuenta que quiero que esto se ejecute como mínimo
cuando se renderiza por primera vez el componente
y además cada vez que cambie el ganador.
Como cada vez que cambia el ganador es cuando gana alguien
y cuando también empezamos de nuevo.
Si yo le doy a empezar de nuevo,
vas a ver aquí que también pone otra vez useEffect.
¿Por qué?
Porque hemos reseteado, ¿ves?
Ahora pone un 2.
Antes ponía un 1, ahora un 2.
Porque ha cambiado el ganador.
Yo puedo seguir jugando
y ahora, pling, un 3.
Y le doy aquí, pling, un 4.
Se ha vuelto a ejecutar porque hemos cambiado.
Le hemos dicho, oye, tengo una dependencia.
Y es que cada vez que cambie el valor de Winner
tienes que ejecutar este código.
Y tú dirás, ¿y esto para qué?
A ver, para un montón de cosas.
Siempre vamos a querer en React ejecutar un efecto.
Es como le vamos a llamar.
Ejecutar un efecto.
Queremos ejecutar efectos cuando cambie cierta información en React.
Por ejemplo, si tenemos un estado, el de Winner,
y queremos enviar una traza,
guardarlo en una base de datos, por ejemplo.
Queremos guardar en la base de datos
quién ha sido el ganador de la partida.
Imagínate que tienes una partida multiplayer.
Oye, pues ha ganado este.
En el useEffect, cuando cambie el Winner, diremos,
ah, pues voy a enviar una petición a una base de datos
para decirle que ha ganado este.
O también, nada más renderizar nuestro componente
para hacer una petición de datos.
O también para hacer un tracking.
O para recuperar información del local storage.
También podríamos decir, oye, cada vez que cambie el board,
voy a guardar esta información.
Y fíjate, esto es muy interesante.
Porque, ¿qué hemos hecho antes?
¿Os acordáis dónde hemos cambiado,
dónde hemos guardado el saveGameToStorage?
Esto lo hemos hecho, lo hemos hecho de forma imperativa.
Porque realmente, hemos dicho, cuando hace esto, hace esto, no sé qué.
Vale, pero es que, ¿cuándo queremos que se guarde la partida?
Queremos que se guarde la partida cuando hay un nuevo turno.
Por lo tanto, una cosa que podríamos hacer es decir,
ostras, pues queremos que guarde, cambie la partida,
cada vez que tenemos un nuevo turno o tenemos un nuevo board,
vamos a decirle que cambie, que guarde la partida.
Podríamos hacer esto, guardar un efecto de que cada vez que cambie el turno
o el board, que guarde la partida.
Esto es una cosa que podríamos hacer, ¿no?
Guardar la partida cada vez que este cambie.
Cada vez que cambie esto, guarda la partida.
Lo que le estamos diciendo es como si nos estuviéramos suscribiendo a un evento.
Muy bien, esto sería un ejemplo.
Pero vamos a hacer un proyectito muy interesante, muy simple,
pero que con un efecto vas a ver la potencia que tiene
y por qué además es interesante, no solo para lo que hemos visto,
sino también incluso para suscribirte a eventos que son del DOM,
como cuando quieres ver si se está haciendo un resize de la pantalla
o para seguir un mouse y tal.
Y ahora te explicaré también por qué haciendo esto se ejecuta dos veces.
Así que voy a guardar los cambios.
ExtractTrackFile, SaveToStorage.
Sincronizamos los cambios.
No te preocupes, solo se puede tener un UseEffect,
no te preocupes que eso también lo vamos a explicar
y no solo se puede tener un UseEffect, se pueden tener más, obvia.
Así que no te preocupes que lo expliques.
Venga, vamos a crear nuestro tercer proyecto.
Pero antes de crear nuestro tercer proyecto,
fíjate que ya antes te he explicado,
oye, vamos a instalar el linter, ¿vale?
Porque sin linter esto es complicadete.
Bueno, vamos a instalar el linter.
Vamos a hacer una cosa.
En la raíz, en todo nuestro proyecto, vamos a hacer un npm install
y vamos a instalar estándar.
Estándar, por si no lo sabes, te lo voy a explicar rápidamente.
Esto, mira, esto es súper importante
porque muchas veces hacéis proyectos sin linter,
hacéis pruebas técnicas sin linter,
no hagáis pruebas técnicas sin linter.
Porque iré a vuestras casas y os arrancaré de un bocado el ojo.
No hagáis eso, ¿vale?
Si hacéis una prueba técnica, el linter es más que obligatorio.
Por favor, que os conozca.
Entonces, vamos a utilizar Standard Yes.
Standard Yes es un conjunto de reglas para linter.
El que puedes utilizar el que tú quieras tu favorito.
Yo te explico este porque es el que a mí me gusta.
Si te gusta otro, utiliza otro.
A mí me gusta este porque es muy fácil y muy rápido de utilizar.
Entonces, voy a utilizar Standard,
que ya tiene unas reglas preestablecidas
de cómo va a linter el código, lo va a formatear.
Entonces, me voy aquí a mi proyecto Aprendiendo React.
Vamos a instalar Standard como dependencia de desarrollo.
Instalarlo, ¿vale?
Y lo vamos a configurar ahora en cuanto...
Entonces, aquí en el Package JSON,
que ya debemos tener aquí el Standard,
vamos a poner Slint Config.
Y aquí vamos a decir Extend.
Y aquí vamos a decirle .barra Modulos,
barra Standard, barra SlintRC.json.
Si no, los componentes de React no los linta bien.
No tengo.
No sé si es una cosa arreglarán en la 18,
pero hasta ahora no está bien.
Si utilizáis StatsScript, también hay esta TS estándar.
No os preocupéis.
Más adelante también lo veremos.
Entonces, con esto y con la extensión que debéis tener también
de Slint, ¿vale?
Porque es compatible con Slint.
O sea, necesitáis la extensión de Slint en vuestro editor.
Ya, al entrar, ya deberíamos detectar, por ejemplo, el app.
¿Ves que ahora me salen aquí un montón de rojos?
Esto es porque el linter me ha dicho, oye,
esto lo tienes con comillas dobles y el linter te dice que son
comillas simples, ¿vale?
Pues yo como tengo el formateador automático en el editor
activado, cuando guarde, me los va a cambiar.
Y así, pues nos vamos a asegurar que nuestro código está bien
formateado, que no tiene errores y seguramente, ves,
aquí te dice, oye, aquí hay espacios que no debería.
Aquí le falta una nueva línea.
Hacemos, ¿vale?
Por lo menos ahora ya tenemos el linter correctamente.
Otra cosa que voy a hacer, voy a crear aquí un gitignore,
que no lo teníamos a nivel de proyecto, ¿vale?
Y voy a decirle que me ignore el package log.json y el
no mode, ¿vale?
Porque así, ves que aquí me pone 4.000, pues así me lo ignorarán.
Y ahora sí, voy a enviar todo esto.
Ay, ay, ay, que la lío.
Add standard link.
Sincronizamos los cambios y ahora creamos el nuevo proyectito,
¿vale?
Para el useEffect.
¿Podemos acceder al código que estás editando?
Sí, golden.
Vamos a verlo una vez más para que nadie se quede atrás, ¿vale?
Tenemos un repositorio donde estamos subiendo todo.
Es este repositorio de aquí.
Lo veis aquí en projects.
Ahora ya tenemos el 1, el 2.
Hicimos un proyecto ya en la anterior.
Ahora tenemos un segundo proyecto.
Si alguien que hace una PR para actualizar esto, pues buenísimo.
Y lo que sí que os pediré es que le dejéis una estrellita,
ya que estáis, ¿no?
Una estrellita, ¿cuántos somos?
1.600.
Hombre, le podéis poner una estrellita.
Así que ponedle una estrellita.
Ponedle una estrellita.
Hostia, ¿qué he hecho?
La he liado, hostia.
Habría puesto la pantalla de la saco.
Pues eso, ponedle una estrellita, ¿vale?
A ver, amigo Yodadev.
Dice, Midu, ¿para qué sirve la función de retorno del UseEffect?
Tío, cálmate.
Si vamos a explicar el UseEffect, ¿tú crees que no explicaremos
para qué sirve la función de retorno del UseEffect?
Yo creo que si no hemos empezado a explicar el UseEffect,
¿cómo me vas a preguntar?
¿Cómo me vas a preguntar eso?
O sea, no te preocupes.
Ya llegaremos a eso.
No vamos a empezar la casa por el tejado.
No tiene sentido.
Vamos a explicar qué es el UseEffect y vamos a verlo todo.
O sea, que no te preocupes.
Dios mío, que qué ansias sois, ¿eh?
Si son unas ansias, es una cosa loca con el ansia.
Ya llegaremos poco a poco.
Venga, vamos, vamos con ello, vamos con ello.
Vamos a crear un tercer proyecto, ¿vale?
Es un proyecto sencillo, pero ya veis que es muy bonito,
muy resultón y que creo que os va a ayudar a entender el UseEffect.
También eso, también eso.
Vamos a Projects.
Vamos a crear nuestro tercer proyecto con bit.latest.
Vamos a poner aquí 03 y vamos a poner, no sé cómo llamarlo,
mouse follower, ¿vale?
React y vamos a poner JavaScript más SW.
Entramos en el 03, mouse follower, npm install,
para instalar las dependencias.
Luego vamos a hacer un monorepo multipaquete, ¿vale?
Para que esto nos vaya más rápido, no tenemos que hacer esto.
Pero al menos por ahora vamos a hacerlo.
Ya tenemos nuestro nuevo proyecto.
Vamos a cerrar el anterior.
Vamos al 03, mouse follower, npm run dev.
Esto nos va a abrir nuestro proyecto, justamente lo mismo,
donde lo teníamos aquí.
Así que refrescamos y ahora nos aparece esto.
Esto es la aplicación por defecto que nos está haciendo bit,
pero lo vamos a quitar porque nosotros queremos hacer
una cosa totalmente distinta.
Así que nos vamos aquí, app.jsx.
Y fíjate, ya tengo el linter funcionando,
ya se quejado un montón de cosas.
Vamos aquí con nuestro proyecto 3.
Quitamos esto, quitamos esto.
Vamos a quitar también el app.
Quitamos y vamos a hacer.
Vale, ya tenemos aquí proyecto 3, ¿vale?
Ya tenemos ahí el proyecto 3.
En el index playflex, vamos a poner que esto sea grid,
para que quede centrado.
Al menos nos debería salir así.
Voy a ver que no me quede yo encima.
No, vale, perfecto.
Muy bien, pues ahora que ya tenemos esto,
ya hemos inicializado todo nuestro proyecto,
vamos a hacer poco a poco este ejercicio con nuestra nueva aplicación, ¿vale?
Va a ser una aplicación sencilla,
pero te vas a dar cuenta que esto es una cosa
que mucha gente hace en sus porfolios
y vas a ver cómo lo hacen,
lo cual le quita bastante magia al asunto, ¿vale?
Entonces, de nuevo, ya sabéis,
yo voy a copiarme todos los estilos.
¿Por qué?
Porque así no tenemos que repetir los estilos desde cero
y perdemos mucho tiempo.
Entonces, los voy a pegar,
pero los voy a subir,
voy a subirte ya el index.css
con los estilos que vamos a usar
para que los uses tú también.
Aunque en este vamos a intentar utilizar pocos estilos
y que los hagamos más en el componente
porque es muy sencillo.
Así que add third project, ¿vale?
Sincronizamos los cambios.
Ya los estoy siguiendo para que los tengas en el repositorio.
Muy bien.
Perfecto.
Pues vamos a empezar.
¿Por dónde empezamos?
Pues primero vamos a empezar con el efecto.
Vamos a tener el efecto
useEffect from React, ¿vale?
Y ya sabemos cómo utilizamos el efecto.
Pues ponemos aquí useEffect.
Vamos a poner console.log.
Vamos a poner aquí efecto, por ahora.
Efecto.
Quitamos esto por acá.
Por ahora dejamos así.
Ahora, vamos a tener...
¿Qué es lo que queremos hacer en este proyecto?
En este proyecto,
lo que queremos es seguir el puntero.
Hay muchos porfolios
que te habrás dado cuenta
que cuando sigues el puntero
hay como una bola alrededor del puntero.
Pues ese efecto
lo vamos a conseguir en este proyecto.
Vamos a hacer un proyecto
en el que pueda seguir el puntero
esa bolita con una animación
bastante bonita
pero que además podemos activar
y desactivar ese efecto.
O sea que vamos a necesitar también
un estado, un useState
donde vamos a poder activar
y desactivar
cuando queremos
que la bolita siga al puntero.
Así que ya tenemos
enable, setEnable
y vamos a poner el botón aquí, ¿vale?
Button
y vamos a poner aquí
activar, seguir, puntero.
Obviamente esto
vamos a hacer que esto se vea bien
que si no se me queja.
Activar, seguir el puntero.
Bueno, tenemos aquí
nuestro botón.
Obviamente tendría que poner
activar o desactivar
dependiendo del estado
de si lo tenemos activo, ¿no?
Así que este activar
vamos a decir
si es enable
tiene que ser desactivar
porque va a hacer lo contrario.
Y si está activo
vamos a decir activar.
O sea, si está desactivado
vamos a poner...
O sea, como ahora es false
pues tendríamos que ponerle activar.
Y si le doy
debería poner desactivar.
¿Cómo hacemos el cambio de estado?
Fácil.
O sea, ya vas a ir viendo
que vamos también
como practicando cosas
que habíamos hecho antes, ¿no?
Bueno, pues tenemos que ponerle
que cuando hacemos clic al botón
¿vale?
Esto ya te lo tienes que saber
vamos, de memoria.
Y aquí sí le decimos
bueno, si estaba activo
pues hacemos lo contrario.
Si está desactivo
lo contrario, ¿vale?
Ahora ya
esto ya lo tenemos, ¿no?
Buenísimo.
Ya tenemos que activar, desactivar.
Mira, me funciona hasta este console.
Fíjate que ya me pone aquí
efecto, ¿vale?
Este efecto se está ejecutando ahora
cada vez que se renderiza.
Muy bien.
O sea que por eso
cada vez que se renderiza
vamos a ver, efecto.
Cada vez que le doy aquí
efecto.
¿Ves que aquí va subiendo
este efecto, efecto, efecto?
Cada vez que se renderiza
efecto, efecto, efecto.
Muy bien.
Si refresco, hay que pena
que esto se queda ahí el 30
y no se puede resetear.
Bueno, nada.
Si no, ¿lo podemos quitar?
Sí.
Vale, lo podemos.
¿Qué es lo que queremos ahora?
Vamos a hacer que este efecto
se ejecute cada vez
que cambia el enable.
O sea que vamos a poner aquí
un console.log
que vamos a poner
que se ejecute
cada vez que se renderiza.
O sea, vamos a poner
el efecto
y para que veas claramente
qué valor tiene el enable
lo vamos a poner.
Como hemos dicho
que tenemos que decirle
al efecto
¿cuándo tiene que ver
que se tiene que ejecutar?
Pues pasando de las dependencias.
Le tenemos que pasar a un array
y le vamos a decir
oye, este efecto
se tiene que ejecutar
cada vez que cambie
el valor de enable.
Y eso va.
Lo guardamos
y fíjate
que ahora
pues se ha renderizado una vez.
¿Vale?
Cada vez que yo le dé
al activar
se va a ejecutar el efecto.
¿Vale?
Otra vez, otra vez.
Cada vez que cambia, cambia.
¿Vale?
Y podemos ver
que la última ejecución
era false.
Cuando le doy
es true.
O sea, ya vemos
cómo el efecto
se está ejecutando correctamente.
Pero, ¿qué es lo que queremos
hacer realmente?
Lo que queremos hacer realmente
es ser capaces
de detectar
cuál es la posición
del ratón
en la pantalla.
Porque vamos a querer
seguirla
y hacer un efecto
que cada vez
que se mueve
nosotros vamos a hacer
como una redondita
que le siga detrás.
Entonces,
vamos a dibujar
la redondita
en un momento.
¿Se os parece?
Vamos a hacer que esto
es un main.
No sé si un main.
O sea, no sé si esto
me va a romper.
No.
Vale.
Vamos a hacer un main
y vamos a hacer la bolita.
Vamos a quitar esto
de proyecto 3
que ya no tiene mucho sentido.
Vamos a hacer la bolita
que va a seguir nuestro...
Hacemos la bolita
donde podemos hacer esto vacío
y vamos a poner ahí
los estilos a saco
para que veáis además
estos estilos
más o menos.
Os sigo en los pocos.
Voy a copiarme los estilos
y así os lo explico
pero no lo hacemos.
Vale.
Vamos a hacer que la bolita
tenga posición absolute.
Que su background,
el color,
sea azul clarito.
Bordes radius de 50%
para hacer que sea
como una redonda total.
La opacidad de 0,8.
Pointer event
se va a hacer que no tenga...
Que si haces clic
en esa redondita
que no os sirva de nada.
Y para centrarlo
lo que hacemos es
ponerle menos 20
tanto a la izquierda
como desde arriba
porque así quedará centrado
en el puntero.
Vamos a hacer que sea menos 20
tanto de arriba
como de la izquierda
que es la mitad
de su ancho y de su alto.
Así quedará centrado.
Y lo único que nos faltaría
es situarlo en algún sitio.
Bueno, ahora mismo
vamos a ponerle
un transform
para decirle
vale, esto me lo trasladas
y lo vamos a poner
en la posición 0 píxel,
0 píxel, ¿no?
Lo vamos a poner por ahí.
Ahora mismo no aparece
porque...
¿Por qué no aparece
mi querido...
El transform lo he puesto?
Vamos a ver.
El div seguro que está.
Así que vamos a ver
por qué no aparece.
Seguiría aparecer...
Bueno, es que igual...
Claro, igual es que está fuera, ¿eh?
Pero bueno, vamos a ver por...
¡Ah!
Style, object, object.
Pero ese object, object
no tiene mucho sentido, ¿no?
Object, object, style...
Este estilo está bien, ¿no?
O sea, le hemos pasado aquí
un objeto.
A ver qué he liado ya.
Pero me parece que ahí
se le ha ido...
Ese object, object,
me parece que se le ha ido, ¿no?
Style, object, object.
A ver, os voy a leer
Ya la tenemos ahí.
¿Por qué no sale?
Vale, gracias, gracias.
Soy mi linter, ¿veis?
Soy mi linter.
Vale, había puesto mal style.
Digo, ¿por qué oye oye?
Vale, ya lo veis ahí.
Está ahí, pero está mal.
O sea, debería seguir el puntero,
obviamente.
Obviamente.
Lo vamos a arreglar.
No os preocupéis.
Con el use effect.
La potencia.
Antes os he explicado
para qué sirve el use effect,
qué cosas podemos hacer,
qué si fetching de datos,
base de datos, tracking,
no sé qué,
mil millones de cosas.
Pero hay otra cosa
que es bastante importante.
También para conectarte
a APIs de terceros.
¿Por qué?
Porque tú en un componente de React,
tú aquí no puedes poner
un window at event listener.
¿Y por qué no puedes hacer esto?
Porque esto,
esto se va a ejecutar
siempre que se renderice
el componente.
Claro,
como el cuerpo de la función
de cada componente en React
se vuelve a ejecutar
cuando se renderiza el componente,
no tendría sentido hacer esto.
Porque cada vez
que se renderice el componente,
se va a volver,
va a hacer un at event listener.
No tiene sentido.
Tenemos que controlar
cuándo nos vamos a suscribir
a un evento.
Y eso lo hacemos
con el usef.
Lo que hacemos con el usef
que es,
oye,
como yo sé
qué código se va a ejecutar aquí
y cuándo,
me voy a suscribir
a los eventos
cuando yo diga.
Y voy a controlar
cuándo me suscriba a un evento,
cuándo hago el fetching de datos,
cuándo hago el tracking.
Voy a tener yo el control.
¿Vale?
No lo hacemos siempre en el render.
Lo hacemos cuando nosotros
sepamos que lo necesitamos.
¿Vale?
Entonces,
lo vamos a hacer
dentro de este efecto,
obviamente.
Y esto,
que va a activar o desactivar
si tenemos que seguir puntero,
obviamente,
bastante importante,
¿no?
Ahora vamos a hacer un
window.atEventListener.
Aquí vamos a hacer
window.atEventListener
y vamos a decir,
bueno,
cuando se mueva el puntero,
pointerMove,
entonces vamos a ejecutar
la función HandleMove.
La función HandleMove
siempre vamos a intentar
que esté dentro del efecto.
Así que vamos a ponerla
aquí,
a su ladito.
¿Y qué va a recibir?
Va a recibir el evento
y el evento,
ya sabéis que el evento
va a tener
tanto el clientX
y el clientY,
que esta es la posición
que tiene nuestro puntero
en la pantalla.
Así que esto
lo vamos a poner.
Por ahora,
no tengo una forma
en la que utilizo
esta información.
Simplemente,
puedo hacer un console.log
y vamos a poner aquí
HandleMove,
ClientX,
ClientY
y verlo en la consola.
Y ahora,
si yo me voy moviendo,
fíjate que va cambiando.
Y si vuelvo aquí,
pues veremos
en el console.log este,
¿vale?
que me ha dado la posición
que me ha dado la posición
de mi puntero.
Y ahora,
cada vez que yo vuelvo aquí,
pues veremos
que va a cambiar.
¿Qué pasa con esto?
Bueno,
que ahora mismo
no estamos utilizando nada,
¿no?
O sea que necesitamos
que esto se guarde
en algún sitio.
Así que vamos a hacer
que eso.
Pero,
fijaos en una cosa también,
que estamos añadiendo
este AdWordsListener
independientemente
si el enable
es true
o no es true.
Esto solo deberíamos hacerlo
si el enable
es true.
Si queremos seguir el puntero,
entonces me suscribo
al evento,
¿vale?
Así que esto,
importante.
Podéis hacer lógica
dentro de un efecto
dependiendo del valor
que tengan nuestras dependencias.
Es totalmente correcto,
tiene todo el sentido
en el mundo,
lo puedes hacer.
Lo que no puedes hacer
es esto.
Si está enable,
hago todo el usef.
Esto sí que no lo puedes hacer.
De nuevo,
no puedes nunca jamás
meter dentro de un condicional
un hook,
sea el useState,
el useEffect
o cualquiera,
todos los que veremos en el futuro
porque lo vamos a ver
todos y cada uno.
Entonces,
esto no lo puedes hacer.
Importante,
esta lógica
la tienes que hacer siempre dentro
y el useEffect
siempre tiene que estar
en el cuerpo del componente.
Si no haces esto,
aparte de que te va a petar,
puede ser que tu renderizado
no funcione como esperas,
¿vale?
Bueno,
ahora que ya tenemos esto,
vamos a ver
qué hacemos
para guardar justamente
la posición
porque parece que funciona o funciona
pero no estamos haciendo nada
con esa posición.
Vamos a guardar aquí,
vamos a tener un nuevo estado,
Position,
Set Position,
UseState
y aquí,
pues,
¿qué podríamos hacer con el UseState?
Podríamos tener ya el objeto,
esto es una buena práctica
que te recomiendo,
que inicialices el estado
con el tipo de dato
que vas a utilizar siempre
o inicializarlo con un null
si es algo que tienes muy claro,
¿no?
De decir,
vale,
null significa que no tengo ese dato
y por lo tanto
voy a controlar
que no tengo ese dato.
Pero una buena práctica,
una buena idea
es que inicialices,
por ejemplo,
si es un string,
si es un objeto
con estos dos parámetros,
esto nos va a decir
dónde está
la posición X y Y
de nuestro cursor.
Pues es una buena idea
que ya lo inicialices con eso.
Ahora,
esta posición X y Y
es la que vamos a utilizar aquí.
En lugar de trasladar
en el 0,
0,
lo que vamos a decir es,
bueno,
pues la posición
va a ser
Position,
vamos a poner aquí
Position.X
y aquí
Position.Y.
Ahora ya estamos utilizando
el estado
y solo nos falta
actualizarlo.
Así que Set Position
y aquí vamos a decirle
Set Position,
la X,
Client X
y la Y,
Client.
Guardamos los cambios
y ahora,
vamos a ver,
claro,
ahora qué pasa,
no me está siguiendo,
¿no?
¿Por qué?
Porque no está activado
lo de seguir puntero.
Si le doy,
fíjate,
además es el mismo efecto
que tiene un montón de gente.
Hay gente que lo hace
con el borde,
que no tiene un background,
que le hace un borde
de dos píxeles,
por ejemplo,
o tres píxeles
lo hacen bastante gordito
y le ponen
a lo mejor aquí
pues que sea más negrita,
esto también lo hacen mucho,
pero bueno,
esto algo así
o igual no tanto algo así,
¿no?
Pero el tema es que
ya estamos haciendo
el mismo efecto,
pero tiene bastantes problemillas
y ahora
vas a ver por qué,
¿vale?
Mira,
ya estamos haciendo esto,
ahora le doy a desactivar,
pero lo sigue,
lo sigue siguiendo.
¿Por qué lo sigue siguiendo
si lo he desactivado?
¿Por qué lo sigue siguiendo
si lo he desactivado?
¿Por qué lo sigue siguiendo
si yo aquí en el UseFek
he dicho,
vale,
si está activado
te tienes que suscribir?
¿Por qué sigue pasando esto?
¿No tiene sentido que haga esto?
No tiene sentido,
¿verdad?
Lo que está pasando aquí
es que este evento
sigue,
sigue estando,
sigue estando
suscrito,
o sea,
piensa que Ria
que hace muchas magias,
pero no es mago,
hace muchas magias
pero no es mago.
Lo que ha pasado
es que nos hemos suscrito
ya a este evento
y en este console log,
aunque yo le he dicho,
mira,
lo vamos a ver otra vez,
¿no?
Al principio
no estamos suscritos,
¿vale?
le doy aquí,
me sigue,
lo desactivo,
todavía me sigue.
¿Qué es lo que pasa?
Que esta suscripción
que hemos dejado aquí
sigue todavía vigente
y esto es súper importante,
las suscripciones
las tenemos que limpiar,
esto es lo que se le llama
como un Clean UseEffect,
es como que tenemos
que limpiar los efectos.
Esto de limpiar efectos,
¿cómo funciona?
Pues que en los UseEffects
puedes devolver una función
y en la función
puedes devolver
cómo limpiar el efecto.
¿Y cuándo se va a ejecutar esto?
¿Cuándo se ejecuta esto?
Pues esto se ejecuta siempre
que se desmonte el componente,
que deje de aparecer el componente,
o sea,
imagínate que este componente app
deja de renderizarse,
pues lo que va a hacer Ria
que es,
vale,
pues voy a ejecutar este método
para asegurarme
que lo limpio todo,
limpio suscripciones,
limpio cualquier cosa
que no necesitemos
y también se va a ejecutar
cada vez que cambie la dependencia.
Cuando cambie la dependencia
va a decir,
vale,
voy a limpiar el efecto anterior
antes de ejecutar el nuevo.
Así empezamos como desde cero,
¿sabes?
Nos aseguramos que empezamos
desde cero.
Así que aquí cuando decimos
¿cuándo se ejecuta esto?
Lo que tenemos que hacer
es limpiar la suscripción
que teníamos antes.
¿Y cómo la limpiamos?
Decimos
window.remove.eventListener
pointer.move.handle.
Lo que hacemos aquí es
vamos a limpiar
la suscripción anterior,
¿vale?
Esto lo vas a ver
que es súper,
esto es un error muy típico
el hecho de no limpiar
las suscripciones
porque te vas a encontrar
que al no limpiarlas
hay muchos problemas
porque no estás limpiándolas
y esto lo que hace es
uno,
que empieza a ir muy mal,
por ejemplo,
imagínate
que no he limpiado las suscripciones.
Ya hemos visto un problema.
Un problema es que yo le doy aquí
y esto sigue funcionando.
Pero hay otro problema
que es un problema
de rendimiento muy grave
y es que cuando tú
no lo limpias
cada vez que le damos aquí
lo que está pasando
es bastante chungo.
Fíjate,
esto empieza a ir mal.
¿Ves que va mal?
Igual hasta el stream va mal.
Va mal
porque se están volviendo
a crear nuevas suscripciones
encima de la anterior.
Esto lo podéis ver
muy claro
con...
A ver cómo era esto.
Ah, sí.
Mira,
esto es un trucazo.
Esto es un trucazo, amigos.
Esto es un trucazo que os voy a explicar.
Mira,
en la consola existe...
Hostia,
¿está petando?
¿Está petando?
¿Está petando?
¿Sí?
No.
Ah,
que está funcionando bien.
Vale.
Bueno,
os voy a enseñar un truco
que esto muy poca gente lo sabe
y que va súper bien
y no es un debugger
ni nada.
Imagínate
que tienes un problema de eventos
como el que estamos teniendo, ¿no?
Imagínate,
yo me estoy suscribiendo aquí
y lo que está pensando
es que esto está teniendo
un crecimiento exponencial
de eventos que se están suscribiendo
y tal.
Bueno,
lineal,
perdón,
y lineal.
Cada vez que le doy
se está volviendo a suscribir y tal.
Bueno,
claro,
¿cómo sé yo realmente
que se están suscribiendo los eventos?
Mira,
hay un método
que se llama
getEventListeners
y le puedes pasar el objeto.
En este caso
le pasamos Windows.
Mira,
aquí puedes ver
cuántas veces
se ha suscrito el pointer move.
Cuatro.
Fíjate
que si yo le sigo dando aquí,
¿vale?
Y ahora vuelvo a mirar,
me va a decir
¿cuántas veces se ha suscrito?
Ocho.
Aquí,
de esta forma,
puedes ver quién se ha suscrito
al elemento Windows
y puedes ver
que tenemos ocho suscripciones
porque no las estamos limpiando.
Esto es un truco maestro
que muy poca gente sabe
y que te permite justamente
detectar
cuando un elemento
se está suscribiendo
y no está limpiando
las suscripciones
o simplemente para ver
quién se está suscribiendo
a ese evento.
Igual hay elementos
que se están suscribiendo
y no debería.
Tienes que evitar
que haya el mínimo número
de suscripciones
porque son bastante costosas,
especialmente,
cuando tienes cientos.
O sea que,
ten cuidado.
Y en este caso
lo podemos ver clarado.
Cada vez que le estamos dando
a esto,
cada vez que le damos,
pues puedes ver
que se añade una más
al pointer.
Si hacemos lo de limpiar
el efecto que hemos dicho antes
y guardamos los cambios
y aquí, pues,
refrescamos,
¿vale?
Ahora vamos a ver aquí
activar, ¿vale?
Ahora,
activo, desactivo,
activo, desactivo, ¿vale?
Vamos a ver cuántos eventos
hay aquí.
Vale,
pues fíjate que ahora
que está desactivado
no hay ninguno.
Si le doy a activar,
ahora sí que debe haber
como mínimo uno.
Vamos a ver, ¿vale?
Ahí tenemos solo uno,
solo tenemos uno.
Si le doy a desactivar,
vamos a ver
que no tenemos ninguno.
O sea,
esto quiere decir
que estamos haciendo bien
la limpieza de los eventos,
que es súper importante.
Estamos limpiando
correctamente los eventos.
Si alguna vez tienes dudas de,
ostras,
estoy limpiando bien el evento,
hay muchos problemas,
no sé qué,
pues lo puedes ver
fácilmente con esto
y lo que tienes que hacer
en el GetEventListeners
es pasarle el elemento
que quieres ver
a ver quién se ha suscrito.
El de Windows
es el que más se suscribe la gente,
así que está bastante bien
que le eches un vistazo
si ves que tu página web
tiene algún tipo de problema
de rendimiento
con el tema de eventos
o para asegurarte
que estás haciéndolo bien
y así,
pues sale, ¿vale?
Ahí tenéis el trucazo
que muy poca gente lo usa.
Eso sí,
eso solo funciona en Chromium,
¿vale?
Eso solo funciona en Chromium,
solo funciona en Chromium.
Entonces,
tenemos que esto es el cleanup
y esto se ejecuta
cuando el componente
se desmonta,
¿vale?
Imagínate que el app
deja de ejecutarse
y ya,
pues decimos,
vale,
pues va a ejecutar el cleanup.
De hecho,
lo podemos mirar.
Vamos a poner aquí cleanup
y también se ejecuta,
se ejecuta
cuando cambian las dependencias,
cuando cambian las dependencias
antes de ejecutar
el efecto de nuevo,
¿vale?
Ahí tenemos cuando se ejecuta el cleanup.
Si guardamos los cambios,
pues lo vais a ver claramente.
¿Cuándo se ejecuta el cleanup?
Vale,
si le damos aquí,
fíjate,
cleanup,
se ha ejecutado ahí,
¿no?
Se ha ejecutado la primera vez.
Pam,
le damos otra vez.
Aquí,
cleanup,
le damos otra vez,
cleanup.
Cada vez que le damos,
como va cambiando enable,
lo que hace es,
vale,
voy a limpiar lo anterior
para asegurarme que hemos limpiado bien el efecto.
Esto en el caso de que os hagáis suscrito algo
y tengáis que limpiar suscripciones
y cosas así,
a veces incluso puede ser útil
para saber,
para enviar una traza,
para hacer analíticas.
¿Por qué?
Porque a lo mejor quiere saber
cuándo un usuario ha cerrado una modal
y la modal,
obviamente,
se cierra del todo
cuando se desmonta.
O sea,
que ahí puede ser interés.
Cuando se desmonta,
claro, alguien puede decir,
bueno,
¿y cuándo se desmonta este componente?
Lo podemos hacer aquí en el main,
podríamos,
bueno,
aquí en el main es un poco complicado,
pero podríamos,
para que veáis cuándo se desmonta este componente,
vamos a separarlo en dos componentes.
Vamos a hacer aquí
que tenemos el follow mouse,
¿vale?
Vamos a poner esto.
Vamos a crear que todo esto esté aquí.
Ah, no,
mira,
mejor.
Vamos a mover parte de una cosa,
la vamos a mover en la otra.
Esto lo vamos a mover aquí
y aquí vamos a poner el follow cursor,
follow mouse,
follow mouse
y esta lógica que tenemos aquí.
Mira,
esto sí que me pongo esto por aquí
y aquí vamos a poner,
vale,
y esto que no le gusta
porque me he olvidado el dip,
he olvidado el dip este.
¿Qué más?
¿Qué más se me ha olvidado por aquí?
Use effect.
Cuando he movido esto,
esto no me ha gustado.
Parsing,
I just think must be graph,
pero tengo este dip aquí.
Ah,
porque lo he cerrado aquí.
Vale,
vale,
ya está,
ya está.
Porque esto tiene que ser con el fragment,
¿vale?
Ya está.
Pensaba que era el dip entero,
pero no,
ese dip era solo de eso.
Vale,
ahora sí.
Bueno,
el tema es que ahora hemos separado
el componente follow mouse
con todo el tema del efecto y todo
y hemos dejado el app
como componente padre.
O sea,
el componente padre está renderizando
el follow.
Entonces,
para que te des cuenta
cuando se ejecuta también el cleanup,
lo que puedes hacer con este ejemplo
es decir,
mount,
mounted,
set mount.
Vamos a poner use state,
le vamos a poner true.
Vamos a ponerle true por dentro,
¿no?
Y le vamos a poner mounted.
Si está montado,
entonces renderizamos el follow mouse.
Y vamos a poner aquí un botón
que sea,
pues,
toggle mounted component
o mounted follow mouse component.
Le ponemos aquí un click.
Esto ya te lo tienes que saber de memoria,
lo del on click,
ya te lo tienes que saber de memoria.
Set mounted
y le decimos not mounted,
¿vale?
¿Qué es lo que hemos hecho?
Hemos hecho un botón
que hace un renderizado condicional
que de forma condicional
renderiza el componente
que sigue el mouse,
¿vale?
Y entonces tenemos aquí,
pues,
dos botones.
Uno para activarlo
de seguir el puntero
y otro que te desmonta
el componente
de seguir el puntero.
Lo bueno de esto
es que ahora verás,
mira,
tenemos aquí el efecto,
cleanup,
efecto.
Y ahora te explicaré,
cuando termine la explicación esta
del toggle,
te explicaré
por qué aparece dos veces el efecto,
¿vale?
Por qué aparece
efecto,
cleanup y effect
justo cuando entramos.
Nada más entrar,
fíjate,
efecto,
cleanup,
efecto.
Hola.
Hola.
Esta tarde he publicado
una oferta en el Discord.
Experto PHP para refactorizar
y convertir PHP monolítico
a React,
Front,
PHP más GSON,
Back,
Teletrabajo,
24-30k euro año
más porcentaje de ventas.
Muy bien,
pues nada,
vuelvan al Discord.
Gracias porque así he podido beber agüita,
que tenía sí.
Muchas gracias.
Entonces,
vamos aquí con el tema.
El tema,
¿por qué estamos haciéndolo del toggle?
Porque quiero que veas
que el cleanup,
el cleanup este,
cuando yo lea el toggle,
va a ejecutarse el cleanup.
Ahora,
lo vuelvo a montar,
cleanup,
¿no?
Siempre que se vuelva a montar el componente,
se va a ejecutar el clean effect
para asegurarse de que
este componente que deja de verse,
voy a limpiarle
el efecto,
todas las suscripciones que tenga.
O sea,
que si tienes un efecto ahí
que tenga una suscripción
y tú tienes ese método,
voy a asegurarme que lo limpio,
¿no?
Cuando desaparece el componente,
cleanup,
¿vale?
Por eso hemos hecho todo esto,
para que lo veáis bastante bien claramente,
¿vale?
Entonces,
bueno,
por ahora vamos a quitar esto del monte
porque no tiene mucho sentido.
Esto era solo para que lo vieseis
y lo entendieseis,
¿vale?
Cuando se ejecuta el cleanup.
Ahora vamos con el tema de,
oye,
¿por qué nada más entrar
hace efecto,
cleanup,
efecto,
esto no tiene sentido?
¿Por qué nada más renderizarse,
se ejecuta el efecto,
luego se limpia
y luego se ejecuta el efecto?
Esto tiene una explicación bastante sencilla.
Y el tema es que,
si vamos al main,
fíjate que tenemos aquí un componente
que se llama
react.strictmode.
¿Qué quiere decir este modo estricto
de react?
Esto es un componente que por defecto
se pone cuando te crea el proyecto
que te sirve mucho
para que te dé advertencias
si estás utilizando código antiguo de react,
si estás haciendo algo incorrecto
y además lo que hace con los efectos
es al montar el componente
ejecuta el efecto,
ejecuta el cleanup
y ejecuta otra vez el efecto.
Y tú dirás,
bueno,
¿y esto para qué lo hace?
Esto lo hace para asegurarse
justamente de que está funcionando bien
tu componente y tu efecto.
Porque si tú ves algo
que funciona mal
cuando tú haces esto,
imagínate que tú haces efecto,
cleanup y efecto
y funciona mal,
por ejemplo,
pues vemos que cuando hacemos esto
vamos a quitar el cleanup.
Imagínate,
nada más entrar
pues resulta
que se hace
que tenemos dos veces el evento.
Vale,
pues ya sé
que hay algo mal
gracias a que el strict mode
lo ha ejecutado dos veces.
Esto es una cosa
que solo se hace en desarrollo,
es como una ayuda
para desarrollar,
¿vale?
No es una ayuda,
no pasa en producción,
o sea que esto
en producción
no lo veríais.
No veríais esto dos veces.
El efecto solo se ejecuta
en modo desarrollo
dos veces
justamente para ayudarte
a desarrollar
y depurar
posibles problemas
que puedas tener,
¿vale?
O sea que ten en cuenta eso,
que este efecto
lo estás viendo así
pero en producción
no lo ves.
De hecho,
si quitamos esto
pues desaparecerá
y solo veremos
el efecto que se ejecuta
a la vez.
Si es algo que por lo que sea
te rayas
o no sé,
te molesta mucho
pues ya sabes
que puedes quitar
el strict mode
sin ningún problema
y así verás
que el efecto
solo se ejecuta
a la vez.
Pero es importante
que sepas
que el strict mode
te ayuda
a asegurarte
que tus efectos
están haciendo la limpieza.
En producción
no ejecutaría
el clean up
de entrada
solo el efecto.
En el strict mode
en producción
el strict mode
no funciona
en producción
o sea,
lo ignora
como si no existiese.
En producción
es como si esto
estuviese así
simplemente
como si estuviese así,
¿vale?
Si estamos en desarrollo
sí que funciona
en producción
no sirve para nada
lo ignora,
¿vale?
Entonces,
bueno,
y si no lo ignora
es porque habéis
enviado a producción
mal vuestro código
porque lo que estáis
haciendo justamente
lo que estáis haciendo
es subir el código
de desarrollo
lo cual tiene mala piel.
Para aseguraros
de que tenéis
el código correcto
vamos a hablar ahora
de,
porque es muy interesante
para el tema
de los efectos
y también lo vamos a ver
con el tic-tac-toe
rápidamente.
Vamos a volver
un momento
al tic-tac-toe,
¿vale?
Vamos a volver
al tic-tac-toe,
vamos al proyecto
del tic-tac-toe,
el juego que hemos hecho
antes,
¿vale?
Y ya tenemos aquí
nuestro tic-tac-toe.
Una cosa que es
súper importante
con todo lo que estamos
viendo
es el tema
de las
React Developer Tool.
Las React Developer Tool
son unas herramientas
de desarrollo totalmente gratuitas
que funcionan en Chrome,
en Firefox,
en cualquier cosa
que sea Creamium,
por ejemplo en Brave
funcionan sin problemas
y le dais aquí a instalar
y ya las tendríais,
¿vale?
¿Qué es lo que nos ofrece
la React Developer Tools?
Lo primero
y que muy poca gente
lo sabe,
pero es muy importante
y muy interesante,
lo primero que ofrece
es que fíjate que aquí,
ahora cuando tengas
las extensiones instaladas
o igual la puedes tener
fuera también,
de hecho la puedes penear
y te la saca fuera,
ves que está como
de color rojo,
pues lo que va a pasar aquí
es que te va a decir
si estás utilizando
el modo desarrollo
o el modo producción
de React.
Esto está muy chulo
porque así rápidamente
nada más viendo
este iconito
vas a ver si la página
está utilizando
el modo desarrollo
o el modo producción.
Por ejemplo,
si me voy a la pngs.dev
que es el proyecto
que hicimos,
ves,
aquí tenemos
el modo producción
y te hace un check,
dice,
oye,
esto está utilizando
el modo producción,
perfecto.
Ahora me voy aquí,
está en rojo,
bueno,
no pasa nada
que esté en rojo,
pero ojo,
que estás utilizando
el modo desarrollo.
Por eso te dice,
la cucaracha
es porque
normalmente
debugger
es para debuggear,
debugger
viene de bug,
de bicho.
Entonces esto es
porque estamos
en modo debugger,
estamos en modo desarrollo,
por eso tiene una cucaracha,
porque estamos
en modo depuración.
Aparte de esto,
esto es muy interesante,
pero tiene más,
obviamente.
Si abres las herramientas
de desarrollo,
aquí veremos
que ahora tenemos
dos pestañitas más,
la de components
y la de profiler.
La de profiler
la veremos más adelante,
pero ahora lo que te voy a explicar
de profiler
es que aquí
es interesante
para temas de rendimiento.
Por ejemplo,
le puedes dar aquí
a reload
and start profiling
y luego lo paramos.
Y esto lo que va a decir
es cuántas veces
se ha renderizado cada cosa
y cuánto tiempo ha tardado
y también te explica
por qué se ha renderizado algo.
Por ejemplo,
si le damos aquí a guardar,
a grabar
y yo empiezo a jugar
y lo paro,
me va a decir,
mira,
se ha renderizado tres veces.
La primera vez
se ha renderizado,
¿por qué se ha renderizado?
Se ha renderizado
porque se ha actualizado,
¿ves?
Ponía por aquí el azul,
se ha renderizado,
a ver si lo encuentro,
Square,
hace un momento lo he visto
y ahora no me sale.
Hace un momento lo había visto
y ahora no sale.
Bueno, pues nada.
Bueno,
lo que podéis ver es que tenéis,
es que este ejemplo
es muy sencillo,
pero no os preocupéis
porque más adelante
en el curso
vamos a ver esto ahora.
¿Qué es lo que ha causado
esta actualización?
Que se ha actualizado app.
Como se ha actualizado app,
también se ha actualizado
el hijo de SquareKey
porque ha cambiado.
Claro,
cada vez que hemos cambiado el valor,
pues hemos visto
que se cambia esto, ¿no?
Esto lo veremos
con más detalle
en una clase más adelante,
¿vale?
Pero ahora mismo
el más interesante
y el que yo creo que está bien
que entiendas
porque es muy simple
pero es súper potente
es este,
que es el de Components.
El de Components además
lo puedes utilizar
en cualquier página.
O sea,
tú puedes ir a Facebook
o puedes ir a la AppGIS
o donde tú quieras
y en principio
puedes utilizarlo, ¿vale?
Puedes utilizarlo aquí,
te vas aquí a Components
y aquí vas a poder ver
todos mis componentes.
¿Qué pasa?
Que en producción normalmente,
en producción normalmente,
lo que vas a ver
es que los nombres
están minificados,
a no ser que
de forma manual
haya puesto
el punto DisplayName
que no suele ser muy típico.
Pero bueno,
al menos puedes ver
las props,
los nombres que tienen las props
y cosas.
Aquí tendríamos
el nombre de las props.
En desarrollo
sí que vais a ver
los nombres de las funciones
totalmente.
Por ejemplo,
aquí tenemos
el componente App
y dentro tenemos
los componentes Square,
Square, Square
y fíjate que además
aquí puedes ver
a cada cual
que se está refiriendo
y ya ves,
aquí tienes el WinnerModal.
Pues lo más interesante
de esto es que
si vamos a la App
vamos a poder ver
tanto los estados
como vamos a poder ver
también las props
y lo vamos a poder cambiar.
Aquí en la App
por ejemplo,
mira el State.
Imagínate que dices,
hostia,
pues voy a cambiar el State.
Vamos a poner que este,
este está aquí también
y lo que deberíamos ver
es cómo se actualiza
y se vuelve a renderizar
nuestro componente.
¿Ves?
He puesto aquí
la bolita.
Venga,
voy a poner
al final del todo,
voy a poner aquí
una X, ¿vale?
Pues me pongo en el 8
y digo, vale,
voy a cambiar el NULL
por justamente la X.
Le doy al Enter,
¡pam!
Esto es súper interesante
porque podemos ver
cómo de replicable
y cómo de increíble
es el hecho
de tener un estado
que podemos modificar
y ver si la UI
responde.
Así que podemos ver esto
y puedes cambiar
cuál es el estado.
Por ejemplo,
imagínate que cambias
el estado del Winner
y decimos,
bueno,
voy a cambiar a ver el Winner,
voy a decir que ha ganado
la Blank.
¡Pum!
¿Ves?
Ha respondido automáticamente
la UI
con el cambio de estado
que hemos hecho aquí a mano.
Podrías replicar,
imagínate que tienes un problema
y te dice alguien,
es que tenía este problema
y ha sido justamente
cuando he hecho este cambio.
Vale,
voy a replicarlo
aunque sea a mano,
aquí.
También lo puedes hacer
cambiando las props.
Imagínate,
vamos a empezar de nuevo.
En este Square,
¿ves?
Tenemos las props.
Children,
Index,
Update.
Veo que aquí
el Children,
ves que está en NULL.
Tú aquí podrías poner A
y aquí tenemos el A.
También puedes cambiar
justamente las props.
Puedes cambiar estados
y puedes cambiar props.
Y además,
también podrías ver,
esto porque es una aplicación
muy sencilla,
pero lo interesante
es que puedes ver
el árbol de componentes,
el árbol de elementos
para ver quién es hijo de qué.
Y esto lo puedes hacer
en cualquier página
que lo acepte.
Por ejemplo,
vamos a Photocast.
También sé que está hecha
con Ria.
Vale,
pues nos vamos aquí.
Madre mía,
cuánto bloqueado.
Deja de espiarme,
Photocasa.
Deja de espiarme,
por favor.
Vale,
pues aquí puedes ver
y mira,
esto sí que tiene nombres.
Por ejemplo,
Share Top Bar.
Lo tienes aquí arriba.
El Share Top Bar.
Podemos ir bajando,
aquí tenemos el Atom Button.
Puedes ir mirando
cada uno de los elementos,
cómo los llaman
y qué significa.
Mira,
Home Inspirational.
Aquí lo tenemos.
Pues es este de aquí.
Este de aquí.
Tenemos que ir Home Inspirational.
Podemos ir bajando
y podríamos cambiarle estados,
podríamos cambiarle las props.
O sea,
podríamos ver cómo se comportaría.
Mira,
la D que dice
Number of Slides,
Show Arrows.
No sé.
En este caso,
como está en producción,
no lo podéis cambiar automáticamente.
Pero si lo tenéis en desarrollo,
ya lo tendréis.
¿Vale?
Pues con esto,
ya tenéis,
con la React Developer Tools,
una forma súper fácil
de poder chequear
las props y estados
para ver cómo se comportan,
qué valores tienen en ese momento,
por si encontráis algún error,
pues ver,
ostras,
cuál es el estado
que tenemos aquí,
¿no?
Vamos a subir esto.
Update repo
with third project.
Vamos a subir esto
y vamos a ver
GitHub aprendiendo,
¿vale?
Vamos a dejar esto por aquí.
Ah, mira,
pull request.
Muchas gracias, hombre.
Update RIM.
Esto con el segundo proyecto.
Venga,
vamos a darle Merch.
Muchas gracias
por haber actualizado el RIM.
CESC.
Muchas gracias.
Y también esto lo ha hecho Amez.
Muchas gracias, Amez.
Espero que no te dé...
Bueno,
no pasa nada.
Nos resolvemos un momento.
Próximamente.
Muy bien.
Muchas gracias.
Gracias, amigos.
Pero ya ves,
hemos hecho dos proyectos prácticos
con los que habéis aprendido
bastante del estado.
Son,
hemos hecho un juego
que no está mal,
hemos hecho una parte
de la interfaz de Twitter
y hemos hecho lo del mouse follower
que parece mentira,
pero eso es una cosa
que muchos porfolios lo hacen
y mucha gente no sabe cómo lo hace.
Pues, bueno,
ya sabéis cómo se hace justamente esto
y además con ese efecto
que te sigue
y que queda súper,
súper finito.
Así que, a ver,
preguntas que tengan
de los efectos y tal
que le damos cañita.
Y ahora practicar.
Bueno,
ahí tenéis tres proyectos.
Ah,
os dejo el repositorio.
Pues,
para que le dejéis,
le podéis dejar una estrellita.
La estrellita,
si llegamos a mil,
nos volvemos locos,
¿eh?
Si volvemos a mil.
Mide una consulta.
¿El curso de GS
lo vas a continuar?
Sí,
lo vamos a continuar.
Siempre inicializado
los estados con un useEffect,
sobre todo cuando tiene que ver
con el localStorage.
¿Crees que está bien?
Claro.
A ver,
Secio,
sí que está bien.
Si utilizamos React
desde el servidor,
cuando queremos leer
del localStorage,
lo tendremos que hacer
en el useEffect.
No lo podremos hacer
directamente en el estado
porque el localStorage
no lo podemos actualizar,
no lo podemos leer
desde el servidor
y petaría.
Entonces,
lo tendrías que hacer
en el useEffect.
¿Se puede ocultar el cursor?
Creo que no,
pero podrías cambiarle el cursor.
O sea,
sí que lo podrías hacer
porque al final
podrías cambiar.
Puedes cambiar,
por ejemplo,
una vez que haces esto,
cuando lo tienes activado,
podrías cambiar el CSS.
No lo voy a cambiar.
Bueno,
podríamos cambiar.
Podríamos cambiarlo.
O sea,
podríamos hacer...
¿Qué podríamos hacer?
Claro,
esto,
es que no tengo claro
si el mouse,
si está aquí.
Claro,
como pone pointerEvents,
pero podrías cambiar
el index.css,
podrías cambiar el cursor.
Podrías con el estado,
podrías decir,
cuando tengo el estado,
no sé qué,
el body,
el cursor,
y aquí podrías utilizar...
Claro,
tienes el default,
pero podrías utilizar el cross...
¿El cross me parece qué?
Cross...
Joder.
Cross mouse pointers.
Es que ahora no me acuerdo
cómo se llamaba.
Cross cursos,
black cross cursos,
HTML,
no,
CSS.
A ver si...
Es que hay un montón,
pero es que ahora no me acuerdo.
Cross hair.
Vale,
esto,
pues podría cambiarlo a este.
¿Ves?
Podría cambiarlo a este
o puedes cambiarlo a alguno
que no se vea mucho,
por ejemplo.
Podría cambiarlo a este
o a alguno que no se vea mucho.
Y eso lo puedes hacer con el estado.
De cuando tengo este estado,
pues cambio este...
También lo podemos hacer
con un efecto.
Muy interesante
porque lo podemos hacer
con un efecto.
O sea,
mira,
lo vamos a hacer
porque está muy chulo
el tema de que veáis
para qué sirven los efectos.
De hecho,
alguien me ha preguntado antes.
Mira,
esto está...
Mira,
esto también es súper importante.
Alguien me ha preguntado antes.
Oye,
¿puedo utilizar dos efectos?
Claro que sí.
Podéis utilizar tantos efectos
como queráis,
¿vale?
Por ejemplo,
podemos tener aquí un efecto...
De hecho,
buena idea,
no intentéis agruparlo todos.
Tenemos aquí un efecto
que es el de el pointer move.
Pointer...
Pointer move,
¿no?
Y podríamos tener otro efecto
que sea el useEffect
y vamos a hacer
que este efecto
sea el de cambiar
change body class.
Y este efecto
también va a tener
la misma dependencia.
Podría tener dependencia
de exteriores.
Podéis tener tantos...
Tantos efectos
como queráis
y como necesitéis.
En este caso...
Bueno, vale.
Tiene mala pinta.
Podemos decir
que document.body.classlist
toggle...
Vamos a poner...
Enable...
Bueno,
no cursor
vamos a poner
no cursor
y esto tiene que ser
si es diferente a Inable.
En este caso...
En este caso...
No sé si tiene...
Claro,
tiene sentido.
Claro,
tiene sentido.
Cuando quitemos esto,
cuando desmontemos
o limpiemos el efecto,
igual sería interesante
eliminar la clase
no cursor.
Así que vamos a hacer esto.
Ahora con esto,
cuando esté activo,
vamos a decirle...
No,
cuando está activo
le decimos no cursor.
Cuando está activo
le decimos
que ponga la clase
no cursor.
Y entonces aquí
vamos a poner
body no cursor.
Vamos a probar el non,
que os he visto
en el chat que lo decías,
no cursor.
Y vamos a ver,
¿ves?
Ahora está activo
y ahora,
fíjate,
ha desaparecido el cursor
y ahora ya lo tenemos otra vez
y ahora desaparece el cursor.
Y esto lo hemos hecho
gracias a un efecto separado.
Podéis tener tantos efectos
como queráis.
Lo hemos hecho,
¿vale?
en este efecto
cada vez que cambia
el enable,
vamos a cambiar
las clases que tiene el body,
le vamos a poner
el no cursor
cuando enable es...
Así que cuando enable es true,
aquí en los elementos,
¿ves?
El body tiene el no cursor.
Cuando lo desactivamos,
ahora no tiene ninguna clave.
Lo volvemos a activar
y para eso
podemos utilizar
un efecto de React.
Fácil y rápido.
¿Has visto?
Y si el usef no tiene dependencia,
¿se ejecuta al montarse
el componente?
Sí,
se ejecuta al montarse
el componente
y, a ver,
que no tenga dependencias
hay que entender una cosa.
Esto hay tres valores,
¿no?
Estaría cuando sería...
O sea,
tendríamos el array vacío
que esto se ejecuta
solo se ejecuta una vez
cuando se monta el componente.
Luego tendríamos el enable
que se ejecuta
cuando cambia enable
y cuando se monta el componente.
Y luego tendríamos
undefined
que se ejecuta
cada vez
que se renderiza
el componente.
¿Vale?
Estas serían los valores,
¿no?
Aquí enable
podrías tener
más dependencias,
obviamente,
pero para que lo entendamos.
Array vacío
solo cuando se monta
el componente.
Array con dependencias
cuando cambia las dependencias
y cuando se monta el componente.
Que no le pasamos nada
se ejecuta cada vez
que se renderiza el componente.
¿Cuál dijiste que era
el objetivo del retorno
en el useEffect?
Limpiar los efectos,
las suscripciones,
por ejemplo.
La única cosa que me ha dejado
con una pequeña duda
ha sido lo de limpiar
el eventListener
al final del useEffect.
Tal y como ya lo había visto,
activabas el eventListener
y justo después lo eliminabas.
Entonces, según mi lógica,
no se debería quedar escuchando.
Es que lo estamos haciendo
dentro de esta función.
Esta función es el
CleanUpMethod
que se ejecuta
cuando el componente
se desmonta
cuando cambian las dependencias.
Esto no lo estoy haciendo aquí.
No lo estoy haciendo fuera.
Lo estoy haciendo dentro
de esta función
que solo se ejecuta
cuando pasan estos.
¿Cómo manejaría
la función de CleanUp
de un useEffect
al hacer una petición HTTP
dentro y que el componente
se desmonta?
Y muy buena pregunta.
Hoy no lo vamos a ver.
Lo haremos otro día.
Pero tenemos una página
que se llama
React.jsWiki
y de hecho esto viene
de un repositorio
que si queréis dejar
esterita también
lo agradezco un montón.
Así que os dejo por ahí
el...
¡Ay!
Me cago en la leche.
¿Otra vez?
¿Qué ha pasado?
Perdonad, ¿eh?
Es que intento pegar una cosa
y no me dejo.
Y entonces me pega
otra cosa rara.
Vale, os dejo ahí
el repositorio.
Aquí tenemos aquí
lo de abortar.
Que esto es lo que dices tú.
¿Cómo puedes abortar
una petición fetch
con useEffect en React?
Aquí tienes la explicación
totalmente en español,
gratis,
totalmente en español
y gratis,
de cómo hacerlo.
Y ves,
utilizaríamos
para que lo veamos rápidamente.
UseEffect
haríamos el fetching de datos
que esto lo haremos
en la siguiente clase
y el clean
lo haremos aquí.
Abortaríamos el fetching aquí.
Esto sería con fetch
pero esto también
lo podrías hacer con axios.
De hecho, no sé
si...
También funcionan axios, ¿ves?
Y esto es un ejemplo
de axios, por ejemplo.
Así es como lo haríamos.
¿No podrías hacer un useStay
para quitar y poner
la clase cursor?
Lo primero es que no sería correcto
y lo segundo es
¿dónde tengo aquí el body?
No lo tengo aquí.
Es algo externo
a este componente.
Entonces, digamos
que es un sideEffect
por lo tanto
no lo podemos hacer.
Tampoco lo podemos hacer
en el cuerpo de la función.
¿Por qué no es buena idea
que aquí en el cuerpo
de la función
lo hagamos?
Primero, porque no es algo
que queremos renderizar
y lo segundo
porque el document
no lo puedes ejecutar aquí
porque document
no existe en el servidor.
Por lo tanto,
es una mala práctica
utilizar document
en el cuerpo de la función.
Lo tenéis que utilizar
en un effect.
¿Cómo saber
cuando se está abusando
de useEffect?
Bueno,
es una buena pregunta.
No es mala pregunta.
Por ejemplo,
se puede abusar
y utilizar mal
el useEffect
cuando la gente
hace cálculos
dentro del useEffect
que fácilmente
se tenían que hacer
aquí dentro.
O cuando se está
regenerando,
se están creando
estados
dentro del useEffect.
Por ejemplo,
es muy fácil
hacer un loop infinito
en el useEffect.
Claro,
si hacéis esto.
Imaginad que hacéis esto
y aquí pones
set,
dices,
if enabled.
No,
mira,
si no está activado,
set position.
¿Sabes?
Como que queréis
hacer esto,
¿no?
Imaginad que queréis
hacer esto.
Esto,
lo que va a ocurrir
es un loop infinito.
No lo voy a guardar
porque petaría,
pero esto es un loop infinito.
¿Por qué?
Dentro del efecto,
actualizas el estado,
no tienes ninguna dependencia,
esto significa que
este efecto
se ejecuta
cada vez
que se renderiza
el componente
y por lo tanto
tienes un loop infinito.
Normalmente,
hacer setStates
cuando no tiene dependencias
tiene mala pinta.
Seguro.
Cuando tiene dependencias,
cuidado.
Por ejemplo,
en los fetch
tiene sentido,
pero tienes que asegurarte
que no haces un loop infinito.
Y luego,
cuando tienes efectos
muy grandes,
por ejemplo,
¿cuándo se abusa
del useEffect?
Cuando en un solo efecto
lo haces todo.
Eso a mí me parece
una mala práctica.
¿Por qué?
Porque tú tienes,
en este caso,
ves que hemos hecho
dos efectos.
Esto puede estar bien
porque luego nos permitirá
separarlo,
luego lo veremos
más adelante
en la siguiente clase,
con dos custom hooks.
Pero lo que pasa
es que si tú lo haces todo
en un solo efecto,
al final quedan muy difíciles
de seguir y de mantener.
Mitu,
gracias por explicar
lo del doble render.
Siempre he pensado
que lo estoy haciendo mal.
No, hombre, no.
Lo ejecutar el cleanup
antes del useEffect
solo pasa en stream mode,
¿verdad?
No.
O sea, cada vez,
eso la primera vez
que se renderiza
el componente,
pero cada vez
que se va a ejecutar
un nuevo efecto,
se ejecuta el cleanup.
Según la documentación oficial,
useEffect no debe usarse
para actualizar estados,
sino que está pensado
para suscribirse a eventos.
Sí y no.
Y la documentación oficial
es un poco polémica.
¿Y por qué?
Porque luego lo explicaremos
en la siguiente clase,
pero muchas veces,
o sea,
el useEffect está bien
que haga actualización
estados.
Por ejemplo,
dice,
te suscribes a un evento.
Claro,
te suscribes a un evento
para actualizar el estado.
Entonces,
si dice exactamente
eso la documentación oficial,
no tiene sentido.
Porque te suscribes
muchas veces a eventos
justamente para setear el estado.
Lo que pasa es que sí que es verdad
que hay que tener en cuenta,
tener cuidado.
O sea,
no tiene mucho...
Esto, algo así,
no tiene sentido.
O sea,
que sea un if
con un set position,
esto no tiene sentido.
Esto tiene mala piso.
Ahora bien,
hay que tenerlo en cuenta.
¿Cómo se cambia
el desarrollo a producción?
Esto es muy fácil.
Simplemente,
npm run build.
Lo que hacemos
es subir este código
que tenemos aquí,
este código.
Nos vamos a
Netlify app.
Netlify app.
Mira,
vamos a hacer un despliegue.
Va.
Netlify drop.
Netlify drop.
Vamos a ver si...
Mira,
drop.
Nos vamos aquí
a lo que nos ha abierto esto.
A ver,
key,
dist,
open,
esto.
Si no estoy mal.
Vamos aquí.
Ahora estamos desplegando
la aplicación que hemos hecho.
Solo hemos ejecutado
npm run build.
Esto nos ha creado
el paquete de nuestra aplicación.
Y mira,
ni me he tenido que...
Pero ha petado.
Ha petado porque...
A ver,
algo no he hecho bien.
Algo no he hecho bien.
No,
pero esto sí que tiene el cat index.
Esto sí que debería...
Algo no he subido bien.
No sé qué no he subido bien.
Pero algo no he subido bien.
No sé si tengo que subir directamente
la carpeta disk.
Igual...
Ah,
igual es que tengo que subir directamente
la carpeta disk.
Vamos a intentar.
Vamos para atrás.
Output folder.
Vale,
es que me dice que...
El folder.
Vale,
vale.
Pues ya está.
Ahora va a funcionar bien.
Esta página está muy chula.
Esta página está muy chula.
¿Qué os parece?
Ya lo tenemos en una URL
desplegado
y lo que hemos hecho
simplemente...
Y fíjate que ahora esto...
¿Ves que ahora está bien?
Si le doy click
me va a decir,
eh,
ya lo tienes en producción.
O sea,
que hemos hecho en un momento
un despliegue a producción
con nuestra querida aplicación.
Y esto mismo
lo podrías hacer con el tic-tac-toe.
O sea,
podemos ir al tic-tac-toe
que dice que no encuentra...
Punto,
Punto,
02,
tic-tac-toe,
npm run build.
Vamos a Netlify Drop.
Nos vamos aquí
a nuestro proyecto.
DIST.
Pillamos la carpeta DIST.
Drop.
Uploading.
Y ya está.
Si queréis que...
Creo que lo mantiene por 24 horas
si no registra...
Ah,
una hora.
Por una hora
si no registráis.
Pero bueno,
os registráis
y entonces lo mantenéis ahí
por los días de los días.
Y ya está.
Ya lo tenemos aquí
en una URL,
en producción
y todo funcionando correctamente.
¿Qué diferencia hay con Bercel?
Pues que es otra marca.
Es como dice...
¿Qué diferencia hay entre Adidas y Nike?
Es otra marca.
Ya está.
Oh my god,
lo que estoy aprendiendo
en un minuto no tiene sentido.
¿Has visto cero críticos?
Hablando de despliegues,
mi edu sé que en ese momento...
Pues si no en ese momento,
si lo sabes,
entonces ya hablaremos otro día.
Mi profesor de JavaScript
me dijo que si quería ejecutar
solo la primera vez
el useEffect,
usar useEffect,
lo hemos explicado antes,
al es the best,
el pasar el array vacío.
¿Se puede utilizar parámetros
en los efectos
como se mandarían?
No,
no se puede utilizar parámetros
en los efectos.
Lo que tienes que...
Lo que tienes
es todas las variables
que están dentro de los scope.
Eso es lo que tendrías.
No le puedes pasar parámetros.
Esta función aquí,
no hay parámetros, ¿vale?
Pero obviamente aquí dentro,
aquí dentro,
puedes acceder, por ejemplo,
a las variables,
a los estados,
a las props,
a constantes que crees aquí
porque están dentro de los scope.
Por lo tanto,
tú aquí puedes acceder a la A
sin ningún problema.
No le puedes pasar un parámetro,
simplemente puedes acceder
a todo lo que tienes
dentro del componente.
Props, estado,
estados que...
Constantes que creas dentro
o fuera del componente,
ese tipo de cosas.
Más adelante verán formularios.
Sí,
seguramente lo veremos
en la siguiente clase.
¿Cómo haríamos para hacer
una petición post
y cada vez actualice una lista?
Eso lo veremos
en la siguiente clase.
¿Se puede retornar
la función de useF
para reseter algo más
que no solo sean suscripciones?
Sí,
de hecho lo hemos visto ya.
Hemos visto el ejemplo del body.
Yo pensaba que la función
de return solo se ejecutaba
a la hora que se desmonta
el componente.
No, no.
¿Lo queréis ver?
Esto es súper importante
y es otro error
que mucha gente...
Es que no sé
si es que no se explica bien
los cursos o no sé.
Pero a ver,
el clean effect
que quede clarísimo,
es que es súper importante
y lo vais a ver aquí.
Es que si le dais aquí
al console lock,
este clean up
se va a ejecutar
no solo cuando se desmonta.
Lo vais a ver claramente
en...
Vamos a quitar esto.
Si yo pongo aquí la consola,
voy a quitar el console lock
del handle mood.
Este,
que ya no lo necesitamos.
¿Ves?
Cada vez que hace el efecto,
cuando vuelve,
va a volver a ejecutar el efecto,
hace un clean up.
Clean up.
¿Ves?
Clean up.
Clean up.
Clean up.
Clean up.
Siempre.
Siempre.
Pero es que tiene sentido.
Tiene sentido.
Siempre va a hacer un clean up.
Esto lo ejecuta
antes de que se desmonte
el componente
y antes de volver a ejecutar el efecto.
Importantísimo.
Hay muchos errores
de mucha gente justamente por esto.
Pero bueno,
esto es lo normal
porque no es lo mismo
haber estado trabajando
siete años con React
en producción
en un producto
de millones de usuarios
que leerte un tutorial.
Es que es normal.
Si haces clean up,
entonces,
¿por qué sigues suscrito al evento?
Bueno,
porque te vuelves a suscribir
en el efecto.
Aquí, ¿no?
Hago el clean up,
quito el evento,
pero luego,
cuando ejecuta el efecto,
dice, vale,
si está activado,
entonces, pues,
a TV Listener.
Es como estamos haciendo la gracia
de cuando el activo está
y cuando el desactivo
ya no está.
Pues así está.
Sí,
bueno, amigos,
no, no,
sí,
ya he explicado
por qué ejecuta el use effect dos veces.
¿Para el despliegue recomiendas Heroku?
No.
Recomiendo Heroku,
Heroku,
Vercell,
Nellify,
Railway,
Renderer,
Fly.io,
pero Heroku no.
Entonces,
¿qué tareas tenéis, amigos?
Porque, hombre,
tendréis que trabajar algo, ¿no?
Que habéis estado aquí un buen rato,
pero, hombre,
alguien ha hecho una pull request,
¿para qué?
Ah,
que no lo he inmergeado esto.
Inmergear.
Vale,
trabajos que tenéis,
trabajos que tenéis.
Primero,
el Tic Tac Toe,
hombre,
el Tic Tac Toe está muy bien,
pero le falta un poco de chicha.
Por ejemplo,
podríais tener por ahí,
darle la vuelta de,
hacer el 4 en línea,
pasar del Tic Tac Toe al 4 en línea,
en lugar del 3 en raya,
que sea el Conecta 4,
¿vale?
A mí eso me parecería muy chulo,
que hagáis el Conecta 4.
Y la lógica es bastante similar,
y así vais a practicar la lógica de programación también.
Porque el Conecta 4,
bueno,
pues tiene que hacer diferentes cosas.
Igual en más grande podéis intentar con uno más pequeño,
ir haciéndolo más grande cada vez.
Así que este es un buen ejercicio,
convertir el 3 en raya en el Conecta 4.
Y además,
pues hacer lo que queráis de mejorar estados,
intentar utilizar el Use Effect dentro del 3 en raya,
¿cómo podríais utilizar el 3 en raya para ello?
Si os animáis podéis hacerlo hasta que sea multiplayer.
No es muy difícil,
pero lo podríais hacer.
Guardar la,
ahora que sabéis el Use Effect,
guardar la información en una API,
por ejemplo,
también lo podríais hacer.
Luego,
del Mouse Follower,
bueno,
el Mouse Follower es bastante sencillo,
pero igual lo que podríais hacer es convertirlo en un juego.
Del hecho de decir que el Mouse Follower,
que si toca alguna cosa,
pues ver cuántas veces toca algo,
cosas así,
por ejemplo,
podrías detectar cada vez que toca el botón,
porque puedes ver el botón cuánto ocupa,
y podrías hacer en clase,
que cada vez que toca algo,
que cambie el sitio.
Eso es un juego que podrías,
mira,
el laberinto,
podríais hacer que de forma random,
dibuje en la pantalla un punto,
que tiene,
y que se va a quedar el punto unos segundos,
con un timeout,
y ver dónde tenéis que poner el timeout.
Y entonces,
podríais hacer ahí el,
el que cuando muevas esto,
si está dentro,
pues te suma un punto en la score.
Y si no,
pues desaparece,
y te sale otro,
y que te den una cuenta atrás,
para ver cuánto llegas a conseguir.
La verdad es que se pueden hacer un montón de cosas.
No vamos a verlo a prueba técnica,
pero porque no me ha dado tiempo,
vino Complity,
no porque sea clickbait,
joder.
Lo vamos a hacer en la siguiente clase,
será lo primero,
en la siguiente clase,
que la haremos la semana que viene,
el miércoles,
a la misma hora.
que la fino las que son chiestas,
tomo en el Perú,
en el made going,
la otra.
Cuando vamos a hacer el tom,
todo lo vamos a hacer,
vamos a hacer especial.