Jan 14, 2019

Diving deep into State and Life Cycle methods of a React Component


Introduction

This article explains what a state is, the life cycle methods of a react component and the use cases of state management.

What is a state?

The main job of React is to take your application state and turn it into DOM nodes.

The key philosophy behind React state is DRY: Don’t Repeat yourself. Figure out the absolute minimal representation of the state your application needs and compute everything else you need on-demand.

Let's talk about what is not a state in React,

  • Is it passed in from a parent via props? If so, it probably isn’t a state!
  • Does it remain unchanged over time? If so, it probably isn’t a state!
  • Can you compute it based on other state or props in your component? Not a state!
  • Props are NOT necessarily states but maybe the parent's state, which means props are static.

React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newbies to understand.

To conclude, State is created in the component and stays in the component. It can be passed to children as its props.

class ParentComponent extends Component {
    state = { count: 0 }
    render() {
        const {count} = this.state;
        return (
            <div>
                <h2>This is my state: { count }</h2>
                <ChildCompoenent count={count} />
            </div>
        )
    }
}

class ChildCompoenent extends Component {
    render() {
        const { count } = this.props;
        return (
            <p>This is my props: { count }. </p>
        )
    }
}

What are the lifecycle methods of a react component?

Lifecycle diagram of React Component

Reference: http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

In this article, I will be covering the most commonly used lifecycle methods which. For details on other methods please refer to this article.

The following are three major phases for a React component:

Mounting

The following methods are called when an instance of a component is being created and inserted into the DOM in the same order.

  • constructor()
  • The constructor for a React component is invoked before it is mounted. Mainly used for initializing state. However, If you don’t want to initialize the state or bind methods then you don’t need to implement constructor for your React component. In the above code super(props) will assign props to this and we are initializing the state of the component.
  • Sample Usage:
constructor(props) {
    super(props);
    this.state = {
        count: 0
    };
}
  • static getDerivedStateFromProps()
  • This method is invoked right before calling the render method. If the state is to be derived from props then we can use this method. We cannot access the instance of the component inside this method. React community strongly recommends NOT to use this. Alternatives for the derived state can be found here:
  • Sample Usage:
static getDerivedStateFromProps({ counter }) {
    return { count: counter + 1  };
}
  • render()
  • This is the only required/mandatory method in your component and all other methods are optional. This should be a pure function and should not modify state. Render function can return either another React element(JSX) or arrays and fragments or strings or portals(to render the children into a different DOM sub-tree) or booleans.
  • Sample Usage:
render() {
  const {count} = this.state;
  return (
      <div>
          <h2>This is my state: { count }</h2>
          <ChildCompoenent count={count} />
      </div>
  )
}
  • componentDidMount()
  • This method is invoked immediately after the component is inserted into the DOM tree. It will be called only once per component. A most common use case of this method is to load data via an Ajax call.
  • Sample Usage:
componentDidMount() {
    axios.get("htttp://getcurrenttimeinutc.com", {
        params: {
            format: "minutes"
        }
    })
    .then((data) => {
        this.setState({
            counterStopsAt: data.time 
        })
    })
    .catch((error) => {
        //log error
    })    
}

Updating

The following methods in this phase are called when an update happens to props or state in the same order.

  • static getDerivedStateFromProps()
  • Same as the Mounting phase getDerivedStateFromProps method.

  • shouldComponentUpdate()
  • By default, React re-renders component on every state/props changes. If we don’t want to re-render the component on a particular prop/state change then we can use this method to prevent re-renders. This method should only return boolean values. Mainly used to tackle performance optimizations. It is highly recommended to use pure components rather than using this method.
  • Sample Usage:
shouldComponentUpdate(nextProps, nextState) {
    return this.props.id == nextProps.id ? false : true
}
  • render()
  • getSnapshotsBeforeUpdate()
  • Invoked right before the most recently rendered output is committed to DOM. It helps in capturing some extra information about the Component like scroll position.
  • componentDidUpdate()
  • This method is invoked immediately after the update occurs. It will not be called on the Initial render. This method gives the opportunity to compare previous props and state before performing an operation. Typical parameters for this method are prevProps and prevState. If getSnapshotsBeforeUpdate is implemented then it will be passed as third parameter else it would be undefined.
  • Sample Usage:
componentDidUpdate(prevProps) {
  // Typical usage (don't forget to compare props):
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

UnMounting

The following method is called when a component is being removed from DOM.

  • componentDidUnMount()
  • This method will be invoked before a component is unmounted or destroyed. Helps to perform clean up if needed.

Why and when do we need state management?

Let's start by understanding the different types of state for a Web Application.

  • Model data →  Data from Database/Backend
  • View/UI state →  Lists, sorting them based on rating
  • Session state →  User’s logged in session
  • Location →  Where we are in the Application, like in which page
  • Relative to time  
  • Long-lasting state →  Application data
  • Ephemeral state →  stuff like the value of an input field that will be wiped away when you hit enter.

 

Reference for the above classification: Front End Masters Course for React-State by Steve Kinney

The user input in one component can affect other components and vice versa. Controlling the flow of data and making sure that all user interface components update accordingly is an error-prone task. In addition, if the components count is high then the maintainability and readability of Code will decrease as you end up passing handlers and state to parent and child components. That's where State Management tools come to the rescue to solve the above problem.

There are quite a few state-management tools out there. Each of the tools solves a unique problem. A few of them are listed below:

  1. Flux
  2. Redux
  3. Redux-Saga
  4. Redux-Thunk
  5. Contexts API

I will be talking more about these tools in my future articles.

Abhilash Reddy Kotte

Frontend Engineering