Crea una cuenta o inicia sesión

¡Continúa aprendiendo sin ningún costo! Únete y comienza a potenciar tu carrera

Métodos del ciclo de vida en React.Component

5/19
Recursos

Aportes 26

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Para complementar esta clase y por qué hay métodos que se dejaron de usar?
.
Antes React utilizaba muchos más metodos para actualizar el estado (siguiente imagen) pero en algun momento a lo mejor se dieron cuenta que era muy complicado porque introducía mucha mas complejidad, codigo repetido y causaba mucha confusión debido a que habían muchos metodos similares, dejo el ciclo de vida con todos los métodos utilizados anetiormente a continuación:

.

Ahora este ciclo de vida se ha reducido y ya no hay tantos pasos para hacer una actualización de estado, por lo que es sencillo entender mas fácilmente cómo se actualiza React, ya no hay tantos pasos intermedios y ya no tendríamos que escribir tanto código si siguieramos utilizando las clases para escribir código. Ya que se han marcado que ya no se deberían usar algunos métodos. Este es el ciclo de vida que se usa ahora:


.
Ahora bien useEffect() recoge lo que hace componentDidMount(), componentDidUpdate(), y componentWillUnmount(), es decir, que useEffect() se encarga de ejecutar un función cuando nuestro componente se va a mostrar ya sea por una actualización o sencillamente porque es la primera vez que se va a mostrar. Si nos fijamos bien componentWillUnmount() es la encargada de eliminar el componente de nuestra interfaz de usuario pues bien con useEffect() tambien se puede utilizar para ejecutar una función una vez nuestro componente se vaya a eliminar esto es útli para: eliminar eventos, hacer una petición al servidor para guardar algo o limpiar algun temporizador. Aunque no se si sea la historia oficial de React 😛 imagino que eso fue lo que pensaron los ingenieros.
.
Pues bien para hacer una comparación de lo que trabajar con clases y useEffect tenemos tres opciones:
.
componentDidMount() Ejecutar algo una vez el componente se inicializa:

useEffect( () => {
  // Algo que se ejecuta dentro
}, []); //Los corchetes para indicar que se ejecute solo la primera vez

.
componentDidUpdate() Ejecutar algo en alguna actualización del estado:

useEffect( () => {
  // Algo que se ejecuta dentro
}, [dependencia]); //Se ejecuta cada vez que la dependencia cambia

componentWillUnmount() Ejecuta algo cuando el componente se va a dejar de mostrar

useEffect( () => {
 window.addEventListener('mousemove', () => {});

 // Una función que se ejecuta despues de que el componente se elimine
 return () => {
   window.removeEventListener('mousemove', () => {})  //Elimina el evento
 }
}, []); 

.
Por último añadir que no se debería usar useEffect sin el arreglo de dependencias (el que se pone al final). Ya que estaríamos ejecutando todo lo que hay dentro en cada nuevo render por lo que agregaríamos calculos que a lo mejor nos podríamos ahorrar.
.
Eso fue todo, espero que te haya gustado Nunca pares de aprender 💚

Comparar el useEffect hook con los Lifecycle de los class components fue la mejor manera para por fin entender este hook. Excelente clase 😄
.
Les comparto este recurso que me ayudo mucho para complementar mas el contenido de esta clase: Replacing Lifecycle methods with React Hooks


💚 Corazoncito si prefieres UseState 😅.
.
Ya en serio, las clases en React son bastante más difíciles de entender, sin embargo al hacer consultas en internet me he encontrado con muchos sitios donde las usan, así que toca aprenderlas de arriba a abajo.

Les dejo un articulo para comprender mas sobre el ciclo de vida de los componentes y la comparación con los hook (estos le dan el ciclo de vida a los componentes funcionales).
https://midu.dev/react-hooks-use-effect-funcionalidad-en-el-ciclo-vida-componentes/

Donde le puedo dar like a esta clase? Me gustó mucho🥹

import React from "react";
import { Loading } from "./Loading";

class ClassState extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      error: true,
      loading: false,
    };
  }

  UNSAFE_componentWillMount() {
    console.log("UNSAFE_componentWillMount");
  }

  componentDidMount() {
    console.log("componentDidMount");
  }

  componentDidUpdate() {
    console.log("Update");

    if(!!this.state.loading) {
      setTimeout(() => {
        console.log("Doing the validation");

        this.setState( { loading: false } );

        console.log("Finishing the validation");
      }, 3000);
    }
  }

  render() {
    return (
      <div>
        <h2>Delete {this.props.name}</h2>

        <p>Please enter the security code</p>

        {this.state.error && (
          <p>Error: Security code is incorrect</p>
        )}

        {this.state.loading && (
          <Loading />
        )}

        <input placeholder="Security Code" />

        <button
          onClick={() => this.setState({ loading: true })}
        >Check</button>
      </div>
    );
  }
}

export {ClassState};
import React from "react";

class Loading extends React.Component {
  componentWillUnmount() {
    console.log("componentWillUnmount");
  }

  render() {
    return (
      <p>Loading...</p>
    );
  }
}

export { Loading };

Este metodo esta deprecado componentWillMount dejara de funcionar con la actualizacion de React 17

Yo se que los Effects son buenos pero, creo que me gustaba más la manera de component, era un poco más clara de pronto es porque aún no comprendo al 100 % los Effect

Bueno saber esto porque en algun momento nos vamos a topar con legacy code

componentDidMount <=> useEffect(() => {}, [])
componentDidUpdate <=> useEffect(() =>{})
componentDisUpdate(prevProps, prevState) <=> useEffect(() =>, [prop1, state1,...])
componentWillUnmount() <=> useEffect(() => { return fn }, [..])

Utilicemos más métodos del ciclo de vida para lograr exactamente el mismo comportamiento y salidas del useEffect por completo. Es decir, hagamos su ejecución inicial (componentDidMount), su validación de nueva ejecución respecto al estado “loading” (shouldComponentUpdate, componentDidUpdate), la limpieza del temporizador (componentWillUnmount y componentDidUpdate), y sus posteriores ejecuciones (componentDidUpdate).

Primero, veamos cómo se comporta el useEffect. Para ello, trabajaremos con el código del curso solo agregándole una función de return para “limpiar el efecto” y algunos console.log para ver en consola las salidas.

useEffect(() => {
    console.log("Beginning effect");

    let timeoutId;

    if (loading) {
      timeoutId = setTimeout(() => {
        console.log("Beginning Validation");

        setLoading(false);

        console.log("Ending Validation");
      }, 3000);
    }

    console.log("Ending Effect");

    return () => {
      clearTimeout(timeoutId);
      console.log("Cleaning Effect");
    };
  }, [loading]);

Y ahora, ¿Cómo logramos la misma salida con las clases?

  1. Su primera ejecución.
    Como sabemos, los efectos se ejecutarán siempre al menos una vez, en el montaje del componente. En las clases logramos esto con el método componentDidMount. Por tanto, nuestro método tendrá exactamente el mismo cuerpo que el useEffect:
componentDidMount() {
    // First time
    console.log("Beginning Component Mounting");

    if (this.state.loading) {
      this.timeoutId = setTimeout(() => {
        console.log("Beginning Validation");

        this.setState({ loading: false });

        console.log("Ending Validation");
      }, 3000);
    }

    console.log("Ending Component Mounting");
  }

Las salidas se cambiaron para diferenciarlas del efecto.

Cabe resaltar que en este caso creamos este método solo para explicación y por ver las salidas que vemos inicialmente en el efecto. Realmente podríamos omitirlo y tendríamos la misma funcionalidad.

Si ejecutamos hasta este punto, tendríamos en consola, lo siguiente:

**
Beginning Component Mounting
Ending Component Mounting
Beginning effect
Ending Effect

**

  1. Sigamos el orden de construcción del efecto y hagamos ahora su función de retorno, conocida como función de limpieza.
    Para ello, en las clases contamos con el método componentWillUnmount. El código de este método es el mismo que la función de limpieza del efecto:
componentWillUnmount() {
  clearTimeout(this.timeoutId);
  console.log("Cleaning Component Desmounting");
}	

Sin embargo, este método casi que nunca (por no decir que nunca xD) se ejecutará, ya que solo lo haría cuando se vaya a desmontar el componente perse.

Es por eso que el profesor lo puso en otro componente que si se desmonta entre renders.

Pero entonces si no se ejecuta este método, ¿Cómo podríamos limpiar lo del render anterior?
Bueno, para ello, necesitamos limpiar después de que se actualiza el componente. Y como sabemos, el método del ciclo de vida que se ejecuta cuando el componente se ha actualizado es: componentDidUpdate. Su código, inicialmente sería:

componentDidUpdate() {
    // Clean up after update (simulate unmount [return function of the effect])
    clearTimeout(this.timeoutId);
    console.log("Cleaning After Component Updating");
  }

Seguramente ya te has dado cuenta, ¡estamos duplicando código! Este es uno de los problemas de los métodos del ciclo de vida.
Probablemente con esto te hayas dado cuenta de que debemos repetir otro código… ¡Exacto! El cuerpo del efecto para que se ejecute en nuevas actualizaciones. Pero antes de eso, veamos cómo podemos evitar una nueva actualización en los componentes de clase.

  1. Con el método shouldComponentUpdate podemos especificar si queremos que un componente se vuelve a actualizar o no, retornando un true o false, respectivamente:
shouldComponentUpdate(nextProps, nextState) {
    // Tip: We can bypass this method by doing the same comparison in the componentDidUpdate method
    if (nextState.loading !== this.state.loading) return true;

    return false;
  }

El problema de este enfoque es que si tuviésemos más props o estados que cambian, deberíamos condicionarlas o sino, el componente solo se actualiza cuando la variable de estado “loading” haya cambiado.

Solo se muestra este método para su conocimiento. React no utiliza este enfoque para evitar aplicar el efecto si ciertos valores (los especificados en el array de dependencias del efecto) no han cambiado. En su lugar, utiliza el método componentDidUpdate para dicha comparación.

**
Ya que conocemos 4 métodos del ciclo de vida, y que hemos logrado el comportamiento de los efectos en su primera ejecución y consideraciones para nuevas ejecuciones, veamos cómo el método componentDidUpdate se encarga de aplicar el efecto en cada nueva actualización.

  1. Copiamos el código del efecto que ya hemos copiado al método componentDidMount al método que se ejecuta después de cada actualización, componentDidUpdate:
componentDidUpdate() {
    // Clean up after update (simulate unmount [return function of the effect])
    clearTimeout(this.timeoutId);
    console.log("Cleaning After Component Updating");

    // New updates (we have to duplicate the code between CDidMount and CDidUpdate)
    console.log("Beginning Component Updating");

    if (this.state.loading) {
      this.timeoutId = setTimeout(() => {
        console.log("Beginning Validation");

        this.setState({ loading: false });

        console.log("Ending Validation");
      }, 3000);
    }

    console.log("Ending Component Updating");
  }

Hemos cambiado las salidas para diferenciar del método componentDidMount.

Vemos una vez más que tuvimos que duplicar código para manejar un mismo comportamiento entre renders. Por este y otros motivos, surgen los Hooks.

Hasta aquí no hemos visto más la consola, pero si ejecutamos ahora nuestro código, veremos que tendremos la misma estructura de salida que con el useEffect al presionar el botón que cambia el estado de “loading” y esperar la ejecución del cuerpo del setTimeout. La consola nos daría el siguiente resultado si probamos los dos componentes (Omitiendo la ejecución inicial):

  1. Con Clases
    ClassState.js:33 Cleaning After Component Updating
    ClassState.js:36 Beginning Component Updating
    ClassState.js:48 Ending Component Updating
    ClassState.js:40 Beginning Validation
    ClassState.js:44 Ending Validation
    ClassState.js:33 Cleaning After Component Updating
    ClassState.js:36 Beginning Component Updating
    ClassState.js:48 Ending Component Updating

  2. Con hooks
    UseState.js:26 Cleaning Effect
    UseState.js:8 Beginning effect
    UseState.js:22 Ending Effect
    UseState.js:14 Beginning Validation
    UseState.js:18 Ending Validation
    UseState.js:26 Cleaning Effect
    UseState.js:8 Beginning effect
    UseState.js:22 Ending Effect


React y el array de dependencias

Antes de terminar, hagamos la validación que se hace en el efecto para decirle a React que omita el aplicar el efecto si ciertos valores no han cambiado entre renders. Esta es la misma que hicimos en el método shouldComponentUpdate pero React la hace en el método componentDidUpdate. Así que eliminamos el shouldComponentUpdate y el código de la clase completa quedaría de la siguiente forma:

export class ClassState extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      error: false,
      loading: false,
    };
  }

  componentDidMount() {
    // First time
    console.log("Beginning Component Mounting");

    if (this.state.loading) {
      this.timeoutId = setTimeout(() => {
        console.log("Beginning Validation");

        this.setState({ loading: false });

        console.log("Ending Validation");
      }, 3000);
    }

    console.log("Ending Component Mounting");
  }

  componentDidUpdate(prevProps, prevState) {
    // Clean up after update (simulate unmount [return function of the effect])
    clearTimeout(this.timeoutId);
    console.log("Cleaning After Component Updating");

    // New updates (we have to duplicate the code between CDidMount and CDidUpdate)
    if (prevState.loading !== this.state.loading) {
      console.log("Beginning Component Updating");

      if (this.state.loading) {
        this.timeoutId = setTimeout(() => {
          console.log("Beginning Validation");

          this.setState({ loading: false });

          console.log("Ending Validation");
        }, 3000);
      }

      console.log("Ending Component Updating");
    }
  }

  componentWillUnmount() {
    clearTimeout(this.timeoutId);
    console.log("Cleaning Component Desmounting");
  }

  render() {
    return (
      <div>
        <h2>Delete {this.props.name}</h2>

        <p>Please, write the security code.</p>

        {this.state.error && <p>Error: security code incorrect</p>}
        {this.state.loading && <p>Loading...</p>}

        <input placeholder="Security code" />
        <button onClick={() => this.setState({ loading: true })}>Check</button>
      </div>
    );
  }
}

No se olviden que no podemos usar funciones expresivas(anónimas o funciones flechas) en componentes con clases.

Mi código para los componentes de clases:

import React, { Fragment } from 'react';
import { Loading } from './Loading';

class ClassState extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      error: false,
      loading: false,
    };
  };

  componentDidMount(){
    console.log('iniciando ciclo de vida del componente');
  }

  componentDidUpdate(){
    this.state.loading ?
    setTimeout(() => {
      this.setState({error: true})
      this.setState({loading:false})
      setTimeout(() => {
        this.setState({error: false})
      }, 3000);
    }, 2000) :
    console.log('Validacion Finalizado.')
  }


  render(){
    return (
      <Fragment>
        <h2>Eliminar {this.props.name}</h2>
        <p>Por favor, escribe el codigo de seguridad.</p>
        <input type="text" placeholder='Codigo de seguridad'/>
        <button
          onClick={() => this.setState({loading:true})}
          className='btn btn-secondary'
        >Comprobar</button>
        {this.state.loading && <Loading />}
        {this.state.error && <p className='bg-danger text-white'>Error: el codigo no es valido.</p>}
      </Fragment>
    )
  }
}

export { ClassState };

Aquí una explicación sobre UseEffect, Dan Abramov, vale todo el tiempo que dediques a leerlo.

https://overreacted.io/es/a-complete-guide-to-useeffect/#cada-render-tiene-sus-propios-effect

Yo preferiría el hook de useEffect, creo que es mas facil de comprender

☯ Comparto mis apuntes sobre Estado y ciclo de vida con React.Component en el siguiente notion

Y recuerden… No siempre vamos a encontrarnos con código moderno y actualizado, entonces siempre es bueno aprender otras formas de desarrollar.

genial premio doble, también aprendo ingles y programación :V

De verdad la carisma del profe Juan motiva a que uno se interese por las herramientas de desarrollo

Quede con la duda al respecto sobre si useEffect en su primera ejecución se puede comparar más la método componentWillMount() o componentDidMount(), así que decidí resolver las duda preguntándole a ChatGPT, lo muestro como aporte, espero pueda servir n.n:
.


Mi pregunta:

¿A que metodos de la clase React.component se puede comparar el hook de useEffect en React?

La respuesta del Bot:

El hook useEffect en React reúne dos métodos de la clase React.Component: componentDidMount y componentDidUpdate.

  • componentDidMount es un método de ciclo de vida que se llama una vez después de que un componente se ha montado en el DOM.
  • componentDidUpdate es un método de ciclo de vida que se llama cada vez que se actualiza un componente y recibe las props previas y el estado previo como argumentos.

El hook useEffect permite a los desarrolladores ejecutar un efecto secundario después de cada renderizado, lo que es equivalente a combinar los comportamientos de componentDidMount y componentDidUpdate. Además, permite controlar cuándo se debe ejecutar el efecto secundario mediante el segundo argumento, que es una dependencia.

En resumen, el hook useEffect combina la funcionalidad de los métodos componentDidMount y componentDidUpdate en una sola API más simple y fácil de usar.

Mi pregunta:

¿ useEffect no usa también el metodo componentWillUnmount ?

La respuesta del Bot:

Sí, el hook useEffect también puede usarse para reemplazar el método componentWillUnmount. Para hacer esto, se debe retornar una función de limpieza dentro del efecto que se desea ejecutar antes de que el componente se desmonte. La función de limpieza se ejecutará automáticamente antes de que el componente se desmonte, permitiéndole realizar cualquier limpieza necesaria.

Aquí hay un ejemplo de cómo se puede usar useEffect para reemplazar el método componentWillUnmount:

import React, { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // Efecto que se ejecutará después de cada renderizado
    console.log('Componente montado');
    
    // Función de limpieza que se ejecutará antes de que el componente se desmonte
    return () => console.log('Componente desmontado');
  }, []); // Segundo argumento: lista de dependencias
  
  return <div>Mi componente</div>;
}

En este ejemplo, el efecto se ejecutará después de cada renderizado y la función de limpieza se ejecutará automáticamente antes de que el componente se desmonte.

.


Espero sea útil este aporte

Les dejo el enlace al diagrama en el que se muestran los diferentes métodos del ciclo de vida de los componentes de React.
Diagrama de los métodos del ciclos de vida en React

Inplemente un API de datos inutiles para que se vizualizen mientras carga, aqui les comparto mi codigo 😃:

import React, { useEffect } from "react";


function UseState({name}){
    const [error,setError] = React.useState(false);
    const [loading,setLoading] = React.useState(false);
    const [fact,setFact] = React.useState("")
    async function fetchData(){
        await fetch("https://uselessfacts.jsph.pl/random.json")
        .then(res=>res.json())
        //.then(data=> console.log(data.text))
        .then(data=> setFact(data.text) )
    }

    useEffect(()=>{
        console.log("Empezando el efecto")
        if(loading){
            fetchData()
            setTimeout( () =>{
           
            setLoading(false)    
        },3000)
    }
        console.log("terminando")
    },[loading])
    
    return (
        <div>
            <h2>Eliminar {name}</h2>
            <p>Por favor escribir el codigo de seguridad para comprobar que lo quieres eliminar</p>
            {error && (
                <p>Error: El codigo es incorrecto</p>
            )}
            {loading && (
                <div>
                <p>Cargando...</p>
                <p>{fact}</p>
                </div>
            )}
            <input placeholder="Codigo de Seguridad"/>
            <button onClick={() => setLoading(true)}>Comprobar</button>
        </div>
    )
}


export {UseState}

ComponentWillMount ya esta deprecado, aca les dejo como cambia y se implementa ahora la misma funcionalidad.

que bueno que apareció useEffect!!!

Ojalá llegue el curso de optimization de react 🙏

Baia, es una excelente clase. Tengo un hermano que trabaja con react y le han dado un proyecto que trabaja con versiones viejas de react. Él me mostró como es el código; en eso pude ver todos los método que va a tener que cambiar.
Realmente la clase te prepara para el trabajo.

Este es mi codigo pero con TS

import { Component } from "react";
import { ClassStateProps, stateComponent } from "../interfaces/interfaces";
import { Loading } from "./Loading";

class ClassState extends Component<ClassStateProps, stateComponent> {
  state: stateComponent = {
    error: false,
    loading: false,
  };

  componentDidMount(): void {
    console.log("Esto dentro del componentDidMount ):????!!!");
  }
  componentDidUpdate(
    prevProps: Readonly<ClassStateProps>,
    prevState: Readonly<stateComponent>,
    snapshot?: any
  ): void {
    console.log("update the component");
    console.log("Esto vale prevProps ", prevProps);
    console.log("Esto vale prevState ", prevState);
    const { loading } = this.state;
    if (loading) {
      setTimeout(() => {
        this.setState({ loading: false });
      }, 3000);
    }
  }
  // UNSAFE_componentWillMount(): void {
  //   console.log("Esto dentro del componentWillMount !!!!!");
  // }
  render() {
    const { name } = this.props;
    return (
      <div>
        <h2> Eliminar {name}</h2>
        <p>Por favor, escribe el codigo de seguridad.</p>
        {this.state.error && (
          <p>
            <strong>Error:</strong> El codigo es incorrecto
          </p>
        )}
        {this.state.loading && <Loading />}
        <input placeholder="Codigo de seguridad" />
        <button onClick={() => this.setState({ loading: !this.state.loading })}>
          Comprobar
        </button>
      </div>
    );
  }
}
export { ClassState };

Se supone que este es el curso para profundizar en estos aspectos de manejos del estado de React. Entonces, esperaba que esos aspectos de optimización del render fuesen cubiertos aquí, en este curso.