Replacing react life cycle methods with react hooks
why should we use Functional Components more
Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class
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.