🖖 Inicio

SERVICIOS

Salir

nochedía

Para qué sirve el hook useEffect en React?

700 palabras
3 minutos
May 8, 2020
blogjavascript

En una frase, nos sirve para ejecutar código cuando una variable cambie, y esto que parece tan trivial, en React sólo podemos hacerlo con este hook

  1. Hooks
  2. Por qué necesito el useEffect
  3. useEffect
  4. Qué pasa cuando no hay dependencias?

Hooks

Los hooks de React son herramientas muy potentes que nos sirven sobre todo para extraer código y poder reutilizarlo de manera muy simple y agradable (tienes documentación oficial aquí: introducción, resumen, referencia)

Con useEffect sin embargo parece que su funcionalidad sea algo opaca

Para qué sirve? Para qué lo necesitamos?

Por qué necesito el useEffect

Para que la respuesta tenga sentido necesitamos pensar como React quiere que pensemos

Más que nada porque sin entender esto, la funcionalidad de useEffect nos podría parecer innecesaria

Viniendo de JavaScript puro, si uno quiere ejecutar una función simplemente la llama y listos, y si quiere que esté ligado a un botón pues con un onClick o utilizando un eventListener ya lo tendríamos

html
<button onClick="miFuncion()">hola</button>
js
const miFuncion = () => console.log('que tal vamos')

Cada vez que apretamos el botón se ejecuta la función y todos tan contentos

Si lo que quisiéramos es que el botón cambiase una variable y que esto cambiase el html, haríamos algo así

html
<button onClick="meDeprimo()">hola</button>
<div id="miestado"></div>
js
const yo = { humor: 'contento' }
document.getElementById('miestado').textContent = yo.humor
const meDeprimo = () => {
yo.humor = 'no tan contento'
document.getElementById('miestado').textContent = yo.humor
}

Lo que está fuera de la función se ejecuta sólo una vez, y lo que está dentro de la función se ejecuta siempre que le demos al botón

La vida era muy sencilla con vainilla JavaScript 🥺😅

Y cuando queremos hacer esto con React, tenemos algo así

js
const MiComponente = () => {
const yo = { humor: 'contento' }
const meDeprimo = () => (yo.humor = 'no tan contento')
return (
<>
<button onClick={meDeprimo}>hola</button>
<div>mi estado: {yo.humor}</div>
</>
)
}

Y tan tranquilos, pero en realidad este código presenta varios problemas, por ejemplo el de la persistencia de yo

Si le incluímos un botón para forzar un re-renderizado, veremos lo que ocurre

js
import React, { useState } from 'react'
export default function App() {
const [, repaint] = useState() // para forzar un repintado
const yo = { humor: 'contento' }
console.log('me acabo de repintar: ' + yo.humor)
const meDeprimo = () => {
yo.humor = 'no tan contento'
console.log('cambiado: ' + yo.humor)
}
return (
<>
<button onClick={meDeprimo}>hola</button>
<div>mi estado: {yo.humor}</div>
<button onClick={repaint}>voy a repintar</button>
</>
)
}

Edit on CodeSandbox

Aquí podrás ver 2 problemas

  • Al apretar el botón hola no hay un repintado que muestre el valor actualizado de yo.humor
  • Y además, al apretar el botón del repintado lo que vemos es que el valor de yo.humor vuelve a ser el del principio, por lo tanto no es persistente

La solución a estos dos problemas es el useState, un hook que es la manera que tenemos en React de utilizar variables que persistan entre re-renderizados

El código React sería éste

js
import React, { useState } from 'react'
export default function App() {
const [, repaint] = useState() // para forzar un repintado
const [yo, setYo] = useState({ humor: 'contento' })
console.log('me acabo de repintar: ' + yo.humor)
const meDeprimo = () => {
setYo({ humor: 'no tan contento' })
console.log('cambiado: ' + yo.humor)
}
return (
<>
<button onClick={meDeprimo}>hola</button>
<div>mi estado: {yo.humor}</div>
<button onClick={repaint}>voy a repintar</button>
</>
)
}

Edit on CodeSandbox

Y puedes ver 2 cosas

  • Que cambiando el estado con el botón hola fuerzas un repintado y efectivamente ves el valor de la variable actualizado
  • Y que forzando el repintado con el botón del repintado no cambias el valor de la variable

Perfecto

👉 Pues hay que interiorizar esta manera de programar, de definir variables con useState, y de tener siempre presente el repintado o rerenderizado

Entonces, si lo que quiero es que el botón sea un contador, y la variable sea el número del contador? Y si también quiero que cuando el contador sea 5 entonces cambie el texto del encabezado?

En realidad podría hacerlo así de simple

js
import React, { useState } from 'react'
export default function App() {
const [, repaint] = useState() // para forzar un repintado
const [counter, setCounter] = useState(0)
const sumarUno = () => setCounter(c => c + 1)
console.log('me acabo de repintar')
return (
<>
<div>{(counter >= 5 && 'CINCO!!!') || 'sigo esperando'}</div>
<button onClick={sumarUno}>Suma Uno!</button>
<div>mi contador: {counter}</div>
<button onClick={repaint}>voy a repintar</button>
</>
)
}

Edit on CodeSandbox

Pero vamos a suponer que queremos hacer algo más complejo y que queremos ponerlo en una función y no dentro del valor que retorna

[ Aquí simplemente actualizo el texto en una variable, pero imagínate cualquier cosa más compleja ]

js
import React, { useState } from 'react'
export default function App() {
const [, repaint] = useState() // para forzar un repintado
const [counter, setCounter] = useState(0)
const sumarUno = () => setCounter(c => c + 1)
const [text, setText] = useState('sigo esperando')
if (counter >= 5) setText('CINCO!!!')
console.log('me acabo de repintar')
return (
<>
<div>{text}</div>
<button onClick={sumarUno}>Suma Uno!</button>
<div>mi contador: {counter}</div>
<button onClick={repaint}>voy a repintar</button>
</>
)
}

Edit on CodeSandbox

Si lo pruebas te salta un error de renders infinitos 🔥🔥🔥🔥🔥🔥🔥🔥🔥

Por qué?

Porque cuando se renderiza al apretar el botón se ejecuta cada vez la línea if (counter >= 5) setText('CINCO!!!')

Y cuando se cumple la condición entonces se altera text con setText('CINCO!!!')

Al cambiar el estado se fuerza otro repaint, que a su vez vuelve a ejecutar esa función, se vuelve a cumplir la condición, etc etc etc y loop infinito

Éste es un problema que sólo existe porque estamos en React, por lo tanto es importante estar en una mentalidad React

Cómo solucionarlo? Con useEffect

useEffect

el hook useEffect nos permite encapsular una función y decirle a react cuándo queremos que se ejecute

La sintaxis es simple

js
useEffect(funcion, [dependencias])
  • La función será lo que queramos que sea
  • Las dependencias serán un array de variables, cuando estas variables cambien la función se ejecutará
  • Y lo suyo es definir la función dentro del useEffect (por x motivos que no hace falta comentar ahora)

Con useEffect el código nos quedaría de la siguiente manera

js
import React, { useState, useEffect } from 'react'
export default function App() {
const [, repaint] = useState() // para forzar un repintado
const [counter, setCounter] = useState(0)
const sumarUno = () => setCounter(c => c + 1)
const [text, setText] = useState('sigo esperando')
useEffect(() => {
if (counter === 5) setText('CINCO!!!')
}, [counter])
console.log('me acabo de repintar')
return (
<>
<div>{text}</div>
<button onClick={sumarUno}>Suma Uno!</button>
<div>mi contador: {counter}</div>
<button onClick={repaint}>voy a repintar</button>
</>
)
}

Edit on CodeSandbox

Y qué hemos arreglado?

Que ahora aunque el componente se re-renderize, la función que está dentro del useEffect no se vuelve a ejecutar

La hemos encapsulado para que sólo se ejecute cuando su dependencia (counter) cambie

Por sí sólo esto podría parecer extraño, pero cuando nos ponemos en modo de pensar React entonces vemos que soluciona un problema específico y muy habitual en React

El hook useEffect nos presenta LA manera de garantizar que algo se ejecute cuando queramos

Sólo queda un detalle más

Qué pasa cuando no hay dependencias?

Si pones un array vacío en el useEffect podrías pensar que ese código no se ejecutará nunca

js
useEffect(() => {
if (counter === 5) setText('CINCO!!!')
}, [])

Y casi aciertas

Un array vacío querrá decir que ese useEffect se ejecutará sólo 1 vez, y esto ocurrirá justo después de que el DOM esté ya disponible

Por lo tanto, el useEffect tiene la particularidad de permitirnos ejecutar código una única vez en nuestra aplicación

Esto, que quizá parezca de poca utilidad, es posiblemente el uso más común de useEffect, esto es, ejecutar código sólo una vez

El ejemplo más típico? Hacer un fetch() de algún recurso, como un login, o leer un archivo, o lo que sea

Listos! 🙋‍♂️

Qué tal la entrada?
👌 Bien 🙌🙌
👍 Bien, pero algunas cosas podrían explicarse mejor 😬
🤷‍♂️ Da por sentadas demasiadas cosas 😒
🤷‍♂️ A ver, hay poca chicha 😬
🤷‍♂️ Los ejemplos no son muy claros 🙇‍♂️
🤷‍♂️ No se entiende, está mal escrito 👎
✍️ Hay errores, revísalo en cuanto puedas 🙏

Newsletter de kuworking, un correo de tanto en cuanto

Quizá te interese

Privacidad
by kuworking.com
[ 2020 >> kuworking ]