En los class components de React.js (los que heredan React.Component ) tenemos acceso a ciertos métodos que nos permiten ejecutar código en diferentes puntos de la vida de un componente. Hay que decir que en los functional components, no tenemos acceso a estos métodos.
Con estos métodos podríamos, por ejemplo, ejecutar código cuando el componente esté recién añadido al DOM o cuando se haya actualizado, también antes de que se elimine, entre otras opciones más.
El diagrama de ejecución de métodos del ciclo de vida de un componente sería éste:
Como puedes ver en el diagrama anterior, los métodos más comunes a los que tendremos acceso (los que están en negrita) son:
- constructor(props): método de JavaScript que se ejecuta antes de que se monte el componente. Lo podemos utilizar para inicializar el estado del componente con this.setState o bindear eventos.
- render(): es el único método requerido en los class components y contiene los componentes que se van a renderizar.
- componentDidMount(): se ejecuta inmediatamente después de que el componente se haya montado. Por ejemplo, lo que podríamos hacer en este método es una llamada a una API.
- componentDidUpdate(prevProps, prevState, snapshot): se ejecuta inmediatamente después de que ocurra una actualización en el componente.
- componentWillUnmount(): se ejecuta inmediatamente después de que un componente se haya desmontado y eliminado.
A los siguientes métodos, también tendremos acceso, pero su uso es menos común:
- shouldComponentUpdate(nextProps, nextState): se ejecuta cuando se hayan actualizado las propiedades o estado y nos permite indicar con true o false, si el componente se tiene que re-renderizar o no.
- static getDerivedStateFromProps(props, state): se ejecuta cada vez que se renderiza un componente. Se devuelve un objeto si se quiere que el estado se actualice y null si no se quiere. Se utiliza cuando el estado depende de las propiedades.
- getSnapshotBeforeUpdate(prevProps, prevState): se ejecuta inmediatamente antes de que el DOM se actualice y nos permite acceder a cierta información del DOM antes de que se hagan los cambios. El valor que se devuelva será pasado a través del parámetro snapshot a componentDidUpdate .
Los siguientes métodos, introducidos en React 16, nos permitirán controlar los errores lanzados desde componentes hijos:
- getDerivedStateFromError(error): recibe el error por parámetro y se devuelve un objeto para actualizar el estado, si no se quiere actualizar el estado se devuelve null. Así, si devolvemos un objeto, podremos acceder al error o a lo que devolvamos en el objeto desde this.state .
- componentDidCatch(error, info): se ejecuta después de que un componente hijo haya lanzado un error.
Si quieres profundizar sobre cada uno de los métodos, echa un vistazo a la documentación de React.js.
Ahora vamos a ver un ejemplo de código en el que utilizaremos los métodos más comunes. Primero de todo, vamos a añadir la posibilidad de eliminar posts del listado del ejemplo anterior, para así, poder ver la ejecución del método componentWillUnmount() .
Vamos al componente PostList.js y añadimos el siguiente código:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
handleDelete = postToDelete => { let posts = this.state.posts.filter(post => post.id !== postToDelete.id); this.setState({ posts: posts }); }; render() { let posts = this.state.posts; return ( ... <PostItem key={post.id} post={post} onDelete={this.handleDelete} /> ... ); } |
Simplemente, añadimos una función que elimina del array de posts del estado, el post que queremos eliminar y después añadimos la nueva lista de posts al estado. También, estamos pasando esta función ( handleDelete ) por la propiedad onDelete al componente hijo PostItem.
Ahora vamos al componente PostItem que debería quedar así:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import React from "react"; import PropTypes from "prop-types"; class PostItem extends React.Component { constructor() { super(); console.log("constructor ejecutado"); } componentDidMount() { console.log("componentDidMount ejecutado"); } componentDidUpdate(prevProps, prevState, snapshot) { console.log("componentDidUpdate ejecutado"); } componentWillUnmount() { console.log("componentWillUnmount ejecutado"); } onDelete = e => { e.preventDefault(); this.props.onDelete(this.props.post); }; render() { console.log("render ejecutado"); return ( <div> <h1>{this.props.post.title}</h1> <p>{this.props.post.content}</p> <button onClick={this.onDelete}>Delete</button> </div> ); } } PostItem.propTypes = { post: PropTypes.shape({ title: PropTypes.string.isRequired, content: PropTypes.string.isRequired }) }; export default PostItem; |
Aquí han cambiado muchas cosas. Primero de todo, antes era un functional component y lo hemos pasado a class component para poder acceder a los métodos del ciclo de vida. Ya que, como hemos comentado antes, los componentes funcionales no tienen acceso a estos métodos.
Después, se han añadido los métodos con unos logs para ver por consola cuando se ejecuta cada uno.
Y finalmente, se ha añadido la funcionalidad de eliminar un post a través de la función pasada por propiedades desde el componente padre (PostList).
Si ejecutamos el código el resultado será éste:
Código completo de la entrada: https://github.com/fullstackseriescom/aprende-reactjs/tree/master/05-ciclo-de-vida
Ejemplo en vivo de la entrada: https://repl.it/@vreaxe/Reactjs-Ciclo-de-vida-de-un-componente
-