React: Understanding State & Lifecycle

May 23, 2019 0 Comments

React: Understanding State & Lifecycle

 

 

In this article we’re going to look at how State & Lifecycle work in React. This knowledge is really powerful, as it helps us separate concerns, add dynamism, and build truly reusable components.

This article is part of a series I’m writing on learning the React fundamentals. Be sure to follow me if you’d like to keep track!

State is used with React Component Classes to make them dynamic. It enables the component to keep track of changing information in between renders. More specifically, the state of a component is an object that holds information that may change over the lifetime of the component.

State v Props

You may wonder how this differs from props? We looked at props in my previous article: React: Components & Props. Recall that props are an object which holds information to control a components behavior. This sounds very similar to state, but lets see how they differ:

  • Props are immutable. Once set they can’t be changed
  • State is observable. It can hold data that may change over time
  • Props can be used in either function or class components
  • State is limited to class components
  • Props are set by the parent component
  • State is updated by event handlers

When using State, we need the state of a component to always exist — so we need to set an initial state. We can do so by defining our state in the constructor of our component class, like so:

class MyClass extends React.Component {
constructor(props){
super(props);
this.state = { attribute : "value"
};
}
}

Note: We’ll look into this code in detail later in this article — under lifecycle methods. For now it’s good to know how we introduce state!

The next thing to know about state is that it should never be explicitly updated. React will use an observable object for state, which allows the component to behave accordingly.

If for example, we we’re to update a components’ state like so:

this.state.attribute = "changed-value";

We’d have a render error! As state wouldn’t be able to detect the changes.

setState()

This is why we use the built-in React method of setState(). It takes a single parameter and expects an object containing our set of values to be updated.

The method will update our state and then call the render() method to re-render the page. Therefore the proper way to update our state, is like so:

this.setState({attribute: “changed-value”});

Remember we’re only ever allowed to define our state explicitly in the constructor — when we provide the initial state.

We can also take advantage of React’s asynchronous abilities by setting multiple states, in one setState() method. A use case for this might be when we want to keep a count (for example — tracking likes of a post or photo).

We could do this using an ES6 arrow function, like so:

this.setState((prevState, props) => ({
total: prevState.count + props.diff
}));

Here we’re taking our previous component state and props, as a parameter, and then we’re updating the total. The same could also be written as a regular function like so:

this.setState(function(prevState, props){ 
return {total: prevState.count + props.diff};
});

In the next section, we’re going to take a look at the React lifecycle. Lets start with a definition..

In general, we might define a lifecycle as birth, growth & death. And our React components follow this cycle as well: they’re created (mounted on the DOM), they experience growth (by updating) and they die (unmounted from the DOM). This is the component lifecycle!

Within the lifecycle of a component, there are different phases. These phases each have their own lifecycle methods. Lets now take a look at these methods.

A component’s lifecycle can be broken down into four parts:

  • Initialization
  • Mounting
  • Updating
  • Unmounting

Lets look at each in detail..

In this phase, our component will be setting its state & props. This is usually done inside a constructor method, like so:

class Initialize extends React.Component {
constructor(props){
    // calling the constructor of its parent
super(props);
    // initialization process
this.state = {
time: new
Date(),
selectedStatus: false
};
}
}

Once the initialization phase completes, we enter the mounting phase. This is when our React component “mounts” on the DOM (its created and inserted into the DOM). This is when our component renders for the first time. The methods available in this phase are componentWillMount() and componentDidMount().

componentWillMount()

This method is called just prior to component mounting on the DOM (or when the render method is called). Then our component gets mounted.

componentDidMount()

This method is called after the component is mounted on the DOM. Like componentWillMount(), it is called only once in a lifecycle. Before its execution, the render method is called. We can make API calls and update the state with the API response.

Lets see these methods in action with an example:

class LifeCycle extends React.Component {
componentWillMount() {
console.log('Component will mount!')
}
componentDidMount() {
console.log('Component did mount!')
this.getData();
}
getData=()=>{
/* method to make an api call for data /
}
render() {
return (
<div>
<h1>Mounting methods in action!</h1>
</div>
);
}
}

After the mounting phase where our component is created, we enter the update phase. This is where component’s state changes and thus, re-rendering takes place.

The data of the component (its state & props) will update in response to user events such as clicking, typing, etc. This results in the re-rendering of the component. The methods we use here are:

shouldComponentUpdate()

This method determines whether the component should be updated or not. By default, it’ll return true. If at some point, if you want to re-render the component on a condition, then shouldComponentUpdate() method would be the correct choice.

If for example, you want to only re-render your component when there is a change in prop — this would be when you use this method. It receives arguments like nextProps and nextState which help us decide whether to re-render by doing a comparison with the current prop value.

componentWillUpdate()

We call this method before re-rendering our component. It is called once after shouldComponentUpdate().If you want to perform a calculation before re-rendering the component & after updating the state and prop, then you would use this method. Like shouldComponentUpdate(), it also receives arguments like nextProps and nextState.

componentDidUpdate()

We call this method after the re-rendering our component. After the updated component gets updated on the DOM, the componentDidUpdate() method executes. This method will receive arguments like prevProps and prevState.

Let’s expand on our previous example:

class LifeCycle extends React.Component {
constructor(props){
super(props);
this.state = {
time: new
Date(),
selectedStatus: false,
list:[]
};
}
  componentWillMount() {
console.log('Component will mount!')
}
componentDidMount() {
console.log('Component did mount!')
this.getList();
}
  getList=()=> {
/
method to make an api call for data */
fetch('https://api.mydomain.com')
.then(response => response.json())
.then(data => this.setState({ list:data }));
}
  shouldComponentUpdate(nextProps, nextState) {
return this.state.list!==nextState.list
}
componentWillUpdate(nextProps, nextState) {
console.log('Component will update!');
}
componentDidUpdate(prevProps, prevState) {
console.log('Component did update!')
}
 render() {
return (
<div>
<h1>Mounting methods in action!</h1>
</div>
);
}
}

The last phase is unmounting. Where our component gets unmounted from the DOM. The method we can use here is:

componentWillUnmount()

We call this method before the unmounting takes place. Before the removal of the component from the DOM, componentWillUnMount() will execute. This method is the end of the component’s lifecycle!

Below is a flowchart neatly displaying all the lifecycle methods:

And that’s it! We’ve covered some important concepts which are fundamental to React. First we looked at State, we compared State to Props, and we looked at how to update and set multiple States. Then we moved on to the React Component Lifecycle, covering the phases (initialization, mounting, updating & unmounting) and the methods available to each.

I hope you found this article useful! You can follow me on Medium. I’m also on Twitter. Feel free to leave any questions in the comments below. I’ll be glad to help out!


Tag cloud