Replacing react life cycle methods with react hooks

why should we use Functional Components more

Satish Kumar
5 min readJun 20, 2020

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class

Photo by Lynda Hinton on Unsplash

Even since react hooks have been introduced in react 16.8, I have been using function components more. class-based components have more overhead compared to the functional components. For example consider this one class-based component

import React from 'react'
class HelloWorld extends React.component{
constructor(props){
super(porps)
this.state = {

}
}
render(){
return <div>
hello world
</div>
}
}

After compiling this code through babel this is what we get

"use strict";var _react = _interopRequireDefault(require("react"));function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }var HelloWorld = /*#__PURE__*/function (_React$component) {
_inherits(HelloWorld, _React$component);
var _super = _createSuper(DisplayMovieList);function HelloWorld(props) {
var _this;
_classCallCheck(this, HelloWorld);_this = _super.call(this, porps);
_this.state = {};
return _this;
}
_createClass(HelloWorld, [{
key: "render",
value: function render() {
return /*#__PURE__*/_react["default"].createElement("div", null, "hello world");
}
}]);
return HelloWorld;
}(_react["default"].component);

which is a lot of code for such a small component.

Now if we consider Functional component

import React from 'react'
function HelloWorld(props){
return <div>
hello
</div>
}

And after compiled through babel

"use strict";var _react = _interopRequireDefault(require("react"));function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }function HelloWorld(props) {
return /*#__PURE__*/_react["default"].createElement("div", null, "hello");
}

which is not much.

So we should definitely be using functional components more and more. this is just one of the many reasons you can find out there. i won't be listing out them here.

But the question is how can we achieve the same functionality provided by life cycle methods in class-based components.

The answer is React Hooks.

let’s consider this class-based component with life cycle methods

import React from 'react'
class HelloWorld extends React.component{

constructor(props){
super(porps)
this.state = {
isOpen:props.isOpen
}
}

getDerivedStateFromProps(props,state){
}
componentDidMount(){

}

render(){
return <div>
hello world
</div>
}

shouldComponentUpdate(nextProps,nextState){
}

componentDidUpdate(prevProps,PrevState){

}


getSnapshotBeforeUpdate(prevProps, prevState){
}

componentWillUnmount(){
}

}

So how can we replace this component with functional component and its life cycle methods with React hooks?

Let’s go through it step by step

constructor, getDerivedStateFromProps, and render:

constructor and render methods are only used in class-based components we don't really need these in functional components. anything done inside the constructor and getDerivedStateFromProp can be done straight forward. and render method is simply replaced with the return statement

import React from 'react'
function HelloWorld(props){
const [isOpen,setIsOpen] = React.useState(props.isOpen) return (<div>
hello
</div>)
}

componentDidMount:

To replace this method we can use useEffect react hook.we just have to pass an empty array to deps.

note: useEffect react hooks can be considered as combined form of componentDidMount, componentDidUpdate and componentWillUnmount

import React from 'react'
function HelloWorld(props){
const [isOpen,setIsOpen] = React.useState(props.isOpen)//works as componentDidMount
React.useEffect(()=>{
const siId= setInterval(()=>{
props.refreshData()
},500)},[])return (<div>
hello
</div>)
}

shouldComponentUpdate:

if any change is detected by react this functional components re-render. if you want to control this behavior you can use React.memo High order component it’s like React.pureComponent(but for function components) but remember that React.memo does the shallow comparison for props only (not for state).(while React.pureComponent for both props and state)

if want to do a deep comparison of prop object you can pass the second argument as the comparison function

function areEqual(prevProps, nextProps){
//return false if you want to re-render else true
}
function HelloWorld(props){
....
......
}export default React.memo(HelloWorld, areEqual)

componentDidUpdate:

this life cycle method is called every time component updates. (After Every re-render)
but it’s not called at first render. on the other hand, useEffect hook is called on the first render also and subsequentially if deps changes.

To achieve completely similar behavior to this life cycle method we have to use two hooks

import React from 'react'
function HelloWorld(props){
. . . .//works as componentDidUpdate
const compDidMount = React.useRef(false)
React.useEffect(()=>{
if(compDidMount.current){
//do something on deps changes
}else{//skip first render(didMount step)
compDidMount.current = true
}},[props.filterValue]). . . .}

useRef hook returns a mutable object here which we use to save flag.

componentWillUnmount:

we can return a function from useEffect which will be called before component unmount.
and do any cleanup in that method.

import React from 'react'
function HelloWorld(props){
const [isOpen,setIsOpen] = React.useState(props.isOpen)//works as componentDidMount and as componentWillUnmount
React.useEffect(()=>{
const siId= setInterval(()=>{
props.refreshData()
return ()=>{
clearInterval(siId)
}},500)},[])//works as componentDidUpdate and as componentWillUnmount
const compDidMount = React.useRef(false)
React.useEffect(()=>{
if(compDidMount.current){
//do something on deps changes
}else{//skip first render(didMount step)
compDidMount.current = true
} return ()=>{
} },[props.filterValue])return (<div>
hello
</div>)
}

there is no replacement for getSnapshotBeforeUpdate, getDerivedStateFromError, componentDidCatch as of now.

If you found this article useful, like and share.

And Have a look at these articles also.

--

--

Satish Kumar

AVP Engineering - frontend Apps at fleetx.io Ex-Aviso Inc. NITian 🎓