Ciclo de vida do React: métodos e ganchos em detalhes

React lifecycle: methods and hooks in detail

The React component lifecycle is an important concept to understand when developing applications with React. It allows developers to control and modify components throughout their lifecycle, from creation to destruction. The react component lifecycle consists of several methods at different stages of a component's existence. Understanding how these methods interact with each other can be (…)

react-lifecycle-hooks-métodos-detalhe

The React component lifecycle is an important concept to understand when developing applications with React. It allows developers to control and modify components throughout their lifecycle, from creation to destruction. The react component lifecycle consists of several methods at different stages of a component's existence. Understanding how these methods interact with each other can be fundamental to creating efficient and maintainable code.

This article will discuss the React component lifecycle, why it is important, and how you can use its various methods effectively in your application development process. I'll look at some of the key concepts behind implementing React lifecycles, including assembly, update, disassembly, and errors. I will also provide examples of how to best use each to gain maximum benefit in terms of performance optimization and bug prevention/resolution.

Before moving on, it's worth noting an interesting fact about React's popularity across the world. According to the latest 2021 Stack Overflow Survey , 42.62% of developers reported using React more than any other library in the past year. This highlights React's position as the right choice for building dynamic and scalable user interfaces.

What is a component in React?

In React, a component is a building block for creating user interfaces. Components are essentially reusable pieces of code that can be combined to create a more complex UI. A component can be thought of as a JavaScript function that returns a piece of code (often called JSX) that represents a part of the UI.

There are two main types of components: functional components and class components. Functional components are simpler and more lightweight, while class components are more powerful and can access more features such as state and lifecycle methods.

Here is an example of a simple and functional component in React:

 import React from 'react';

 function Greeting(props) {
 return (
  <h1>Hello, {props.name}!</h1>
 );
 }

 export default Greeting;

In this example, the Greeting component is a functional component that takes a name and returns an h1 element with the message “Hello,name!”.

The React component lifecycle

Are you new to React development and wondering how to manage the state of your components? Or maybe you're an experienced developer looking to optimize your code and improve the user experience. Whatever your level of knowledge, understanding the React component lifecycle is fundamental to building robust and efficient applications. In this section, we will look at the different stages of the component lifecycle and the methods associated with each stage.

reaction life cycle

By the end, you'll have a solid understanding of how components work in React by following a case-based, step-by-step example so you're well-equipped to build dynamic, engaging user interfaces.

The React component lifecycle can be divided into three main phases: Assembly, Update and Disassembly. Each phase has several methods invoked at specific points in the component's life cycle.

Let's now look at a table that summarizes the different stages of the React component lifecycle and the methods associated with each stage:

Life Cycle Stage Methods
Assembly constructor

static getDerivedStateFromProps

render

componentDidMount

Updating static getDerivedStateFromProps

shouldComponentUpdate

render

getSnapshotBeforeUpdate

componentDidUpdate

Disassembling componentWillUnmount
Error handling static getDerivedStateFromError

componentDidCatch

Now that we know the lifecycle stages of a React component, let's explore each of its methods in more detail to gain a deeper understanding of how they work and what they are used for.

Assembly

The assembly phase occurs when a component is created and inserted into the DOM. During this phase, the following methods are invoked:

constructor

When a component is created, the constructor method is the first to be called. It is used to initialize component state and bind event handlers.

 class MyComponent extends React.Component {
 constructor(props) {
  super(props);
  this.state = {
   count: 0
  };
  this.handleClick = this.handleClick.bind(this);
 }

 handleClick {
  this.setState({ count: this.state.count + 1 });
 }

 render {
  return (
   <div>
    <p>You clicked {this.state.count} times</p>
    <button onClick={this.handleClick}>Click me</button>
   </div>
  );
 }
 }

getDerivedStateFromProps

This method is called right after the constructor, allowing the component to update its state based on changes to its props. This method must return an object to update the state or null if no update is required.

 class MyComponent extends React.Component { 
static getDerivedStateFromProps(nextProps, prevState) {
 if (nextProps.value !== prevState.value) {
 return { value: nextProps.value };
 }
 return null;
 }

 constructor(props) {
 super(props);
 this.state = {
 value: props.value
 };
 }

 render {
 return <div>{this.state.value}</div>;
 }
 }

render

This method is responsible for rendering the component's UI. Must return a React element, a JSX expression, or a call to React.createElement .

 class MyComponent extends React.Component {
 render {
 return <div>Hello, {this.props.name}!</div>;
 }
 }

componentDidMount

This method is called after the component is rendered for the first time. It performs any side effects, such as fetching data from an API or setting up event listeners.

 class MyComponent extends React.Component {
 componentDidMount {
  fetch('
   .then(response => response.json )
   .then(data => this.setState({ data }));
 }
  
render {
 return (
 <div>
 {this.state.data ? (
 <ul>
 {this.state.data.map(item => <li key={item.id}>{item.name}</li>)}
 </ul>
 ) : (
 <p>Loading data...</p>
 )}
 </div>
 );
 }
 }

Updating

The update phase occurs when the properties or state of a component changes. During this phase, the following methods are invoked:

getDerivedStateFromProps

This method is called again if the component properties change. It works the same way as in the assembly phase, allowing the component to update its state based on changes to its props.

 class MyComponent extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    if (nextProps.value !== prevState.value) {
      return {
        value: nextProps.value
      };
    } 
return null;
 }

 constructor(props) {
 super(props);
 this.state = {
 value: props.value
 };
 }

 render {
 return < div > {
 this.state.value
 } < /div>;
 }
 }

shouldComponentUpdate

This method is called before the component is updated, allowing the component to determine whether to re-render. It must return a boolean value indicating whether the component should be updated or not.

 class MyComponent extends React.Component {
 shouldComponentUpdate(nextProps, nextState) {
  return nextProps.value !== this.props.value;
 }

 render {
  return <div>{this.props.value}</div>;
 }
 }

render

This method will be called again if the component is rendered again. It should return a new React element that reflects the updated state of the component.

 class MyComponent extends React.Component {
 render { 
return <div>Hello, {this.props.name}!</div>;
 }
 }

getSnapshotBeforeUpdate

This method is called right before the component is updated and allows the component to capture some information from the DOM before it changes. This information is then passed to componentDidUpdate .

 class MyComponent extends React.Component {
 getSnapshotBeforeUpdate(prevProps, prevState) {
  if (prevProps.value !== this.props.value) {
   return this.myRef.current.getBoundingClientRect .top;
  }
  return null;
 }

 componentDidUpdate(prevProps, prevState, snapshot) {
  if (snapshot !== null) {
   console.log(`Element was ${snapshot}px from the top`);
  }
 }

 render {
  return <div ref={this.myRef}>Hello, {this.props.name}!</div>;
 }
 }

componentDidUpdate

This method is called after the component is updated. It is used to perform any side effects like updating the DOM or dispatching an action to a Redux store.

class MyComponent extends React.Component {
 componentDidUpdate(prevProps, prevState) {
  if (prevProps.value !== this.props.value) {
   this.props.onValueChange(this.props.value);
  }
 }

 render {
  return <div>{this.props.value}</div>;
 }
 }

Disassembling

The disassembly phase occurs when a component is removed from the DOM. During this phase, the following method is invoked.

componentWillUnmount

The componentWillUnmount method is called right before the component is removed from the DOM. It is used to perform any cleanup tasks, such as removing event listeners or canceling API requests.

 class MyComponent extends React.Component {
 componentDidMount {
  this.intervalId = setInterval( => {
   this.setState({ time: new Date });
  }, 1000);
 }

 componentWillUnmount {
  clearInterval(this.intervalId);
 }

 render {
  return <div>The time is {this.state.time.toLocaleTimeString }.</div>;
 }
 }

In addition to lifecycle methods for creating, updating, and removing components, React provides two methods for error handling: static getDerivedStateFromError and componentDidCatch .

Error handling

React components can also experience errors during their lifecycle. An error in a child component can propagate to the parent component. To handle these errors, React provides two methods.

static getDerivedStateFromError

The static getDerivedStateFromError method is a lifecycle method called when there is an error during rendering, in the lifecycle methods of child components, or in the constructors of any child components. It allows the component to update its state with an error message, which can then be used to render a replacement UI.

 class MyComponent extends React.Component {
 static getDerivedStateFromError(error) {
  return { hasError: true };
 }

 constructor(props) {
  super(props); 
this.state = { hasError: false };
 }

 render {
 if (this.state.hasError) {
 return <div>Something went wrong.</div>;
 }

 return <div>{this.props.children}</div>;
 }
 }

 class App extends React.Component {
 render {
 return (
 <MyComponent>
 <ChildComponent />
 </MyComponent>
 );
 }
 }

componentDidCatch

The componentDidCatch method is a lifecycle method called when an error is detected in a child component. It allows the component to perform side effects such as logging the error or sending an error report to a server.

 class MyComponent extends React.Component {
 constructor(props) {
  super(props);
  this.state = { hasError: false };
 }

 componentDidCatch(error, info) {
  // Log the error to an error reporting service
  logErrorToMyService(error, info.componentStack);
 }

 render {
  if (this.state.hasError) { 
return <div>Something went wrong.</div>;
 }

 return <div>{this.props.children}</div>;
 }
 }

 class App extends React.Component {
 render {
 return (
 <MyComponent>
 <ChildComponent />
 </MyComponent>
 );
 }
 }

React component lifecycle example: a WeatherApp

react-lifecycle-weather-app-mockup

After understanding how React component lifecycle methods work and what they are used for, let's put this knowledge into practice with an example. In this tutorial, we'll create a simple React app that displays the current weather based on the user's location. We'll explore how to use component lifecycle methods to handle assembly, updating, disassembly, and error handling, providing a real-world example of integrating these concepts into your applications.

Prerequisites

Before we begin, make sure you have the following installed on your computer:

  • Node.js (version 10 or higher)
  • npm (version 6 or higher)
  • A react code editor of your choice (e.g. Visual Studio Code)

Starting

To get started, open your terminal and create a new React app using the create-react-app command:

 npx create-react-app weather-app

After the application is created, navigate to the project directory and start the development server:

 cd weather-app
 npm start

Your application should now be running at http://localhost:3000 .

react-lifecycle-methods-example-app

Creating the WeatherApp component

To create the WeatherApp component, create a new file called WeatherApp.js in the src folder. Open the src/App.js file in your code editor and replace the existing code with the following.

 import React from 'react';
 import Weather from './components/Weather';

 function App {
 return (
  <div className="App">
   <WeatherApp />
  </div>
 );
 }

 export default App;

Now add the following code to the src/WeatherApp.js file.

import React, { Component } from 'react';

 class WeatherApp extends Component {
 render {
  return (
   <div>
    <h1>Current Weather</h1>
   </div>
  );
 }
 }

 export default WeatherApp;

This creates a simple React component that renders a title.

react-lifecycle-methods-example-weather-app

Handling user location

To search for the user's location, we will use the Geolocation API provided by the browser. We will use the componentDidMount lifecycle method to fetch the location when the component is mounted.

 import React, { Component } from 'react';

 class WeatherApp extends Component {
 constructor(props) {
  super(props);
  this.state = {
   latitude: null,
   longitude: null
  };
 }

 componentDidMount {
  navigator.geolocation.getCurrentPosition(
   (position) => {
    const { latitude, longitude } = position.coords;
    this.setState({ latitude, longitude });
   },
   (error) => {
    console.error(error); 
}
 );
 }

 render {
 const { latitude, longitude } = this.state;

 return (
 <div>
 <h1>Current Weather</h1>
 <p>Latitude: {latitude}</p>
 <p>Longitude: {longitude}</p>
 </div>
 );
 }
 }

 export default WeatherApp;

In the componentDidMount method, we use the Geolocation API's getCurrentPosition method to fetch the user's location. This method requires two callbacks: one to handle success and one to handle error. If the location is obtained successfully, we update the component state with the latitude and longitude values. If there is an error, we log it to the console.

In the render method, we render the latitude and longitude values ​​of the component state.

react-lifecycle-example-current climate

Searching weather data

To fetch the current weather data based on the user's location, we will use the OpenWeatherMap API. We will use the fetch method to make the API request. We will also use the componentDidMount method to fetch the weather data when the component is mounted.

 import React, { Component } from 'react';

 const API_KEY = 'YOUR_API_KEY';

 class WeatherApp extends Component {
 constructor(props) {
 super(props);
 this.state = {
  latitude: null,
  longitude: null,
  weatherData: null
 };
 }

 componentDidMount {
 // Fetch the user's location
 navigator.geolocation.getCurrentPosition(
  (position) => {
   const { latitude, longitude } = position.coords;
   this.setState({ latitude, longitude });

   // Fetch the weather data
   const url = `
   fetch(url)
    .then(response => response.json )
    .then(data => this.setState({ weatherData: data }))
    .catch(error => console.error(error));
  },
  (error) => { 
console.error(error);
 }
 );
 }
 render {
 const { latitude, longitude, weatherData } = this.state;

 return (
 <div>
 <h1>Current Weather</h1>
 {latitude Longitude && (
 <p>
 Latitude: {latitude}, Longitude: {longitude}
 </p>
 )}
 { weatherData && (
 <div>
 <p>Temperature: {weatherData.current.temperature}°C</p>
 <p>Description: {weatherData.current.weather_descriptions(0)}</p>
 </div>
 )}
 </div>
 );
 }
 }

 export default WeatherApp;

In the componentDidMount method, we first fetch the user's location using the getCurrentPosition method. Once we have the latitude and longitude values, we will use them to construct the API request URL. We also pass in our API key and set the units parameter to metric to get temperature values ​​in Celsius.

We then use the fetch method to make the API request. We use the then method to handle the response and convert it to JSON format. We then update the component state with the weather data. If there is an error, we log it to the console.

In the render method, we conditionally render latitude and longitude values ​​and weather data based on their existence in the component state.

current weather-reaction life cycle example with location

Error handling

Finally, let's address errors that can occur during the component's life cycle. We will use the static getDerivedStateFromError and componentDidCatch methods to handle errors.

 import React, { Component } from 'react';

 const API_KEY = 'YOUR_API_KEY';

 class WeatherApp extends Component {
 constructor(props) {
  super(props);
  this.state = {
   latitude: null,
   longitude: null,
   weatherData: null
  };
 }

 componentDidMount {
  // Fetch the user's location
  navigator.geolocation.getCurrentPosition(
   (position) => {
    const { latitude, longitude } = position.coords;
    this.setState({ latitude, longitude });

    // Fetch the weather data
    const url = `
    fetch(url)
     .then(response => response.json )
     .then(data => this.setState({ weatherData: data }))
     .catch(error => console.error(error));
   },
   (error) => {
    console.error(error); 
}
 );
 }

 static getDerivedStateFromError(error) {
 return { error: error.message };
 }

 componentDidCatch(error, info) {
 console.error(error);
 console.error(info);
 }

 render {
 const { latitude, longitude, weatherData, error } = this.state;

 return (
 <div>
 <h1>Current Weather</h1>
 {error? (
 <p>Something went wrong: {error}</p>
 ) : (
 <>
 {latitude Longitude && (
 <p>
 Latitude: {latitude}, Longitude: {longitude}
 </p>
 )}
 { weatherData && (
 <div>
 <p>Temperature: {weatherData.current.temperature}°C</p>
 <p>Description: {weatherData.current.weather_descriptions(0)}</p>
 </div>
 )} 
</>
 )}
 </div>
 );
 }
 }

 export default WeatherApp;

In the constructor, we added a new state property called error that we will use to store any errors that occur during the component's lifecycle.

In the componentDidMount method, we add a catch block to handle errors when fetching weather data. We set the error state property to the error message if an error occurs.

We also use the setState method to set the latitude and longitude state properties when we successfully fetch the user's location.

The static getDerivedStateFromError method is called when an error occurs in any child component of the current component. This method must return an object to update the component's state. In our example, we simply update the error state property with the error message.

The componentDidCatch method is called when an error occurs in any child component of the current component and is used to log the error to the console. In our example, we log the error and the component's stack trace to the console.

Finally, in the render method, we use the error state property to conditionally render an error message if an error occurs. Otherwise, we display the user's location and current weather data if available.

Conclusion

In conclusion, understanding and effectively implementing the React component lifecycle is essential for building efficient, scalable, and maintainable applications. As we've seen, lifecycle methods give developers fine-grained control over the behavior of their components, allowing them to optimize performance, manage state, and handle errors. By leveraging assembly, update, and disassembly methods, developers can create complex user interfaces that are responsive and efficient.

If you liked this article about React, check out these topics;

  • React best practices
  • React UI component libraries
  • Top 6 React IDEs and Editors
  • React vs Backbone JS
  • Why is React so popular?
  • What you need to know about react
  • React WebSockets: Tutorial

Frequently Asked Questions (FAQ)

What are the three main component lifecycle methods?

The three main component lifecycle methods in React are assembly, update, and disassembly.

Why do we use React lifecycle methods?

We use React lifecycle methods to handle different stages of a component's life, such as initialization, rendering, updating, and destruction, and to perform specific actions or add specific behavior during each stage.

What is the difference between React hooks and lifecycle methods?

React hooks provide a more concise way to manage state and side effects in functional components. Lifecycle methods are only available on class components and can connect to multiple stages of a component's lifecycle.

Source: BairesDev

Back to blog

Leave a comment

Please note, comments need to be approved before they are published.