Bruno R
Considerando el ciclo de vida de las clases de React y sus metodos, useEffect es un equivalente a: componentDidMount, componentDidUpdate y componentWillUnmount combinados.
Existen dos tipos de “efectos secundarios” en React, los que requieren de una operacion de cleanup y los que no.
Luego de la actualizacion del DOM por parte de React, podriamos ejecutar codigo adicional. Peticiones de red, mutaciones manuales del DOM y registos, serian ejemplos de efectos que no requieren un cleanup.
El metodo render no deberia causar efectos secundarios por si mismo, esto podria ser algo prematuro (dependiendo del estado del DOM en ese mismo momento… buscamos usar los efectos despues de que react haya actualizado el DOM).
Por esta razon se usan los metodos componentDidMount (para aplicar el efecto al cargar el componente por primera vez en el DOM), y componentDidUpdate (para iniciar el efecto una vez actualizado el componente).
class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; }
componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; }
render() { return ( <div> <p>You clicked {this.state.count} times</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> </div> ); } }
En este ejemplo react cambia el titlo del documento justo despues de que react realiza cambios en el dom.
El codigo se encuentra duplicado porque queremos que ocurra el efecto tanto para cuando se monta el componente por primera vez o si el estado fue actualizado.
Conceptualmente lo que buscamos es que el efecto ocurra en cada renderizado del componente, pero los componente de clases no tienen un metodo asi.
import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Cuando utilizamos este hook, el componente debe hacer algo luego de renderizarse. React recordara la funcion que le hemos pasado y la llamara cuando se actualice el DOM, (podriamos usarla para por ejemplo, realizar peticiones de datos, o invocar alguna API).
Se hace asi para acceder a la variable de estado, count (o cualquier prop), directamente desde el efecto sin necesidad de una API especial para acceder a ella, (ya que se encuentra en el ambito de la funcion).
Por defecto si, se ejecuta despues del primer render y cada actualizacion del component, este comportamiento es modificable…
Algunos efectos necesitan limpiar los datos antes de usar un efecto, un ejemplo serian establecer una suscripcion a una fuente de datos externa. En estos casos es IMPORTANTE limpiar el efecto para no producir una fuga de memoria.
En las clases react se utilizan DidMount para establecer una suscripcion, y WillUnmount para cancelarla.
class FriendStatus extends React.Component { constructor(props) { super(props); this.state = { isOnline: null }; this.handleStatusChange = this.handleStatusChange.bind(this); }
componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); }
handleStatusChange(status) { this.setState({ isOnline: status.isOnline }); } render() { if (this.state.isOnline === null) { return 'Loading...'; } return this.state.isOnline ? 'Online' : 'Offline'; } }
En este ejemplo se utiliza una supuesta ChatAPI para evaluar los datos con los que se pintara en pantalla un resultado u otro en el render, ahora lo interesante aca es que tenemos que repetir el codigo en ambos metodos de clase a pesar de que el efecto sea el mismo la logica cambia y por esto se deber reperir.
Ademas en este ejemplo para ser considerado correcto tambien deberia contener el metodo componentDidUpdate, entonces se repetiria una vez mas