Categories
JavaScript React

State and Lifecycle of React Components

Spread the love

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at the lifecycle of React components and how to change their internal state.

Changing Internal State

Props are immutable since we want to keep React components pure with respect to props. This means that when we pass in the same props, we always get the same output assuming nothing else changes.

This isn’t very useful in most cases since we want to change things inside a component.

To do this, we can manipulate the internal state of a component.

All class-based React components have internal state accessible via this.state, and we can change it by calling this.setState.

For example, if we want to create a Clock component that shows the current time and updates it every second, we can do that as follows:

class Clock extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { date: new Date(), timer: undefined };  
  } 

  componentWillMount() {  
    this.updateDate();  
  } 

  componentWillUnmount() {  
    clearInterval(this.state.timer);  
  } 

  updateDate() {  
    const timer = setInterval(() => {  
      this.setState({ date: new Date() });  
    }, 1000);  
    this.setState({ timer });  
  } 

  render() {  
    return (  
      <div>  
        <p>It is {this.state.date.toLocaleTimeString()}.</p>  
      </div>  
    );  
  }  
}

In the code above, we declared a class Clock that extends React.Component. This means the code is a React component, which can have its own lifecycle methods and the render method.

Inside the Clock component, we declared the state field in the constructor which has the initial state date, and a timer state to hold the timer object that’s returned by setInterval.

Also, we called super(props) since Clock extends React.Component, and the React.Constructor takes props as an argument.

Then we have our componentDidMount lifecycle hook to load the initialization code when the Clock component is mounted into the DOM.

The updateDate method is called in componentDidMount to continuously update the this.state.date every second.

To update the date inside the setInterval callback, we called this.setState with an object inside.

The object has the state’s name as the key as we defined it in the first line, and the value is the new value that we want to set the state to.

We also called setState to set the timer field so that we can call clearInterval with it inside the componentWillUnmount. The componentWillUnmount hook is called when the component is removed from the DOM.

It’s a good place to run any code that’s used to clean things up.

Finally, in the render method, we render the date. This method is called whenever this.state changes by calling this.setState, so if we put this.state properties in there, the latest value of it will always be shown.

This means that this.state.date will be the latest date after:

this.setState({ date: new Date() });

is called.

componentDidMount and componentWillUnmount are lifecycle methods. They’re called only in specific parts of a React component’s lifecycle.

this.setState is asynchronous, so we shouldn’t assume that code that’s listed after a this.setstate call will run immediately after this.setState.

To mount it in the DOM, we call the ReactDOM.render method with Clock passed in as follows:

import React from "react";  
import ReactDOM from "react-dom";

class Clock extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { date: new Date(), timer: undefined };  
  } 

  componentWillMount() {  
    this.updateDate();  
  } 

  componentWillUnmount() {  
    clearInterval(this.state.timer);  
  } 

  updateDate() {  
    const timer = setInterval(() => {  
      this.setState({ date: new Date() });  
    }, 1000);  
    this.setState({ timer });  
  } 

  render() {  
    return (  
      <div>  
        <p>It is {this.state.date.toLocaleTimeString()}.</p>  
      </div>  
    );  
  }  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<Clock />, rootElement);

Using State Correctly

We should never modify the state directly because it won’t trigger a re-rendering of a component.

So we shouldn’t write:

this.state.foo = 'bar';

Instead, we should always use this.setState as follows:

this.setState({foo: 'bar'});

State Updates May Be Asynchronous

State updates are asynchronous, so we shouldn’t depend on it run one after the other.

Also, we can’t just combine props and state values within setState .

For example, the following may fail:

this.setState({  
  count: this.state.count + this.props.increment,  
});

Instead, we write:

this.setState((state, props) => ({  
  count: state.count + props.increment  
}));

to get the latest values from props to update the code.

Regular and arrow functions both work, so we can also write:

this.setState(function(state, props) {  
  return {  
    count: state.count + props.increment  
  };  
});

State Updates are Merged

When we call setState, React merges the object that we pass into setState into the current state.

For example, if we have 2 states, firstName and lastName, then when we called this.setstate({ lastName });, this.state.firstName stays intact, while this.state.lastName is updated with the latest value of lastName.

Data Flows Down

States are always inside a component, and it can be passed down to child components and elements as props.

React apps has a unidirectional data flow that goes from parent to child.

Conclusion

We can create a React component that is dynamic by storing states inside a component.

The state object is stored in the state field of the React component class.

We can set the state by running this.setState.

React components have lifecycles that trigger methods in the React component class. These are called lifecycle hooks.

We can use them to run code at certain stages of a React component’s lifecycle.

Leave a Reply

Your email address will not be published. Required fields are marked *