48

Casos Prácticos de useEffect y useLayoutEffect en React

49094Puntos

hace 3 años

Los React Hooks useEffecty useLayoutEffect son efectos que protegen partes de nuestros componentes para evitar que se ejecuten en cada render, sino únicamente cuando realmente los necesitamos.

Efectos vs. ciclo de vida

Usando clases y React.Component hacíamos este mismo trabajo con los métodos del ciclo de vida: componentDidMount, componentDidUpdate y componentWillUnmount.

Usando funciones, efectos y React Hooks podemos replicar este comportamiento de la siguiente forma con useEffect:

useEffect(() => {
	/*
		componentDidMount 
		Para que se ejecute alguna acción solo cuando se monta el componente en pantalla, el
		segundo parámetro de useEffect debe ser un Array vacío. 
	*//*
		componentDidUpdate
		El componente se actualiza solo si el segundo parámetro de useEffect es un array con
		el valor que se espera que cambie.
	*/return () => {
		/*
		  componentWillUnmount
		  Aquí describes todo evento al que hayas suscrito el componente, de no haberlo
		  hecho, no es necesario agregar el return al final de la función.
		*/
	}
},[])

También podemos usar useLayoutEffect. Es muy similar a useEffect, aunque no los usamos muy seguido debido que tienen una pequeña diferencia: useLayoutEffect es un llamado de manera síncrona después de todas las mutaciones del DOM (profundizaremos esto más adelante), mientras que useEffect no.

Si es la primera vez que escuchas sobre este hook verás que en código es lo mismo que su compañero, solo cambia el nombre:

useLayoutEffect(() => {
	return () => {
	}
}, [])

💡 Puedes tener múltiples hooks de efecto en un solo componente

Diferencias entre useEffect y useLayoutEffect

useEffect

Este hook se ejecuta de manera asíncrona después de ser renderizado y mostrado el componente en pantalla.

Este es el paso a paso que sucede con tu componente cuando estás usando este hook:

  1. El estado del componente cambia
  2. El componente se vuelve a renderizar
  3. El componente es mostrado en pantalla
  4. useEffect se ejecuta

useLayoutEffect

Por otro lado, useLayoutEffect se ejecuta de manera síncrona después de que se tenga el render del componente, pero ANTES de ser pintado en pantalla.

⚠️ Todo lo que hagas con este hook hará que el paint del componente tarde más de lo esperado, lo cual puede afectar el performance.

Ahora verás que pasa con tu componente:

  1. El estado del componente cambia
  2. El componente se vuelve a renderizar
  3. useLayoutEffect se ejecuta y React espera a que termine
  4. El componente es mostrado en pantalla

¿Cuándo usar cada uno?

Hay un par de consideraciones al momento de usar uno u otro, recuerda:

  • Si necesitas manipular algún elemento del DOM antes de que sea mostrado en pantalla, useLayoutEffect te servirá mucho
  • Si requieres que tus componentes se vean fluidos y no presentan una especie de “parpadeo” cada que cambia el estado, usa useLayoutEffect (con precaución)
  • Y de manera muy general, useEffect te será útil para todos los demás casos

¡Manos a la obra!

Vamos a poner en práctica ambos React Hooks con un par de ejemplos para estudiar mejor sus diferencias.

Manipula elementos del DOM antes de que sean mostrados

React soporta el agregar manejadores de eventos para el click, focus, select directamente a los componentes de la siguiente forma:

Aunque también existen alternativas como hacer un addEventListener al elemento deseado (sí, justo como lo haríamos en vanilla JS). Pero en React no podemos hacer algo como document.querySelector('#button'), ya que no es lo ideal. En cambio, tenemos useRef otro React Hook que nos permite acceder a elementos del DOM de manera sencilla.

Vamos a crear un componente como cualquier otro y con useRef junto con useLayoutEffect agregaremos manejadores de eventos.

import { useRef, useLayoutRef, useState } from'react'exportconst MyDummieComponent = () => {
	  const [state, setState] = useState()

	  const printDate = () => {
		//La función hará algo muy sencillo, imprime en pantalla la fecha actual
		setState(newDate().toTimeString())
	  }
		
	  useLayoutEffect(() => {
	      //Al agregarlos con LayoutEffect nos aseguramos que los manejadores de eventos//estén disponibles una vez el boton sea mostrado
		  buttonRef.current.addEventListener("click", printDate)
		  
		  return() => buttonRef.current.removeEventListener("click", printDate)
		  // En este caso agregarás la función de limpiado para remover el eventlistener // una vez desaparezca el componente
	  }, [])
	
	  const buttonRef = useRef(null)

	  return(
		<div><h1>{state}h1><buttonref={buttonRef}> Check date button>div>
	)
  }


🧑‍💻 Visita el ejemplo en Codepen

Evita que tus componentes tengan una alteración visual cuando cambian de estado

Si has tenido que cambiar múltiples veces el estado de algún componente en un corto periodo de tiempo, tal vez hayas notado que tiene una ligera variación cuando usas useEffect. Afortunadamente, hay una alternativa para corregir esta situación. Haz un componente dummie que solo te de un número aleatorio cada que hagas click sobre él.

Para percibir de mejor manera el cambio que se tiene entre estos dos hooks, te apoyarás de un interval que ejecutará el cambio de estado del componente.

import { useState, useLayoutEffect } from'react'exportconst RandomNumbers = () => {
	// Inicializa el estado de nuestro componenteconst [number, setNumber] = useState(0)
	
	//En este caso usarás el segundo hook, intenta ver el cambio que tiene ejecutándolo//con useEffect
	useLayoutEffect(() => {
		//Aquí solo te aseguras que el efecto se efectúe solo si el number es 0if(number === 0){
			setNumber(10 * Math.random() * 200 + Math.random())
		}
		// En el array ponemos el estado para ejecutar el hook cuando cambie
	}, [number])

	const createInterval = () => {
	// este interval ayudará a ver mejor lo que pasa con useLayoutEffect y useEffectlet intervalTest = setInterval(() => {
		  setInterval(0)
	  }, 10)
	
	// El timeout es para evitar problemas con el interval y dejar de ejecutarlo a los// 10 segundos
	  setTimeout(() => {
		clearInterval(intervalTest)
	  },10000)
	}

	return(
		<div><p>{number}p><buttononClick={() => setNumber(0)}>Change numberbutton><buttononClick={createInterval}>Run testbutton>div>
	)
}


Visita el Codepen con useEffect.
Visita el Codepen con useLayoutEffect.

Juega un poco con este componente y verás esa pequeña diferencia que existe entre un hook del otro, solo debes cambiar useLayoutEffect de useEffect y viceversa. 😉

Conclusiones

Como te habrás dado cuenta, useLayoutEffect solo lo usarás en muy contadas ocasiones y estará ahí para auxiliarte cuando tengas problemas con useEffect o cuando necesites acceder a un nodo del DOM antes de que sea mostrado en pantalla.

Si quieres aprender React.js de manera profesional, te recomiendo la siguiente ruta de cursos donde conocerás los React Hooks mucho más a fondo y con proyectos extremadamente prácticos:

#NuncaParesDeAprender

Leonardo de los angeles
Leonardo de los angeles
LeoCode0

49094Puntos

hace 3 años

Todas sus entradas
Escribe tu comentario
+ 2
3
18385Puntos

El 99% de las veces querrás usar el hook useEffect y el hook useState para manipular la salida de un componente React.
.
Pero en ciertos casos, cuando debes realizar cambios directamente en un nodo DOM. En caso de que lo necesites, sigue éstas 2 reglas generales:

  1. Utiliza useRefsi necesitas manipular el focus, la selección de texto, activar animaciones imperativas o integrar bibliotecas de terceros.

.

  1. Utiliza el useLayoutEffectcuando sea que necesites usaruseRef