To cope with the ongoing demand of ReactJs, the developer’s community of this library has been upgrading this library frequently to make it more usable and performance-friendly. In React Conf 2018, a significant change has been introduced to this library called hooks and available from React V16.8.0. In short, it has changed the way of developing applications with ReactJs on a big scale. In this article, we are gonna be discussing the basic usage of Basic Hooks.
Motivation of hooks
Previously, when we were using lifecycle methods, everything was looking fine, and no obstacle we were facing to develop a particular application. So it is a common question of newbies or maybe some experienced developers too that, why did we have to introduce React Hooks? Well, a straightforward answer to that question is, we did not require this hook unless we are concerned about faster development and better performance of the system in a production environment. These hooks have enabled us to have:
1. Better readability
2. Less code for the development
3. Performance enhancement for production.
When we used to use class components, there we had to think about the constructor, binding of ‘this,’ different life cycle methods. More importantly, as it was a class-based component, whenever we tried to use any state of that class, we had to worry about binding the state with the reference of the class. Also, in previous versions, we had no option to use state in our functional component. But now, as React has introduced hooks, we can now use the states and lifecycle methods in our functional component. So, the class component is no longer essential; in fact, not at all needed to develop an application with ReactJS, which increases the readability of the code as now, we have exactly what we need.
To use state in a functional component, now we have a hook which is useState. This is one of the most interesting features of ReactHooks. Let’s see the usage of this hook:
useState returns an array consisting of two objects.
1. State itself
2. A function to update the state.
const [count, setCount] = useState(10);
Here, the first element of the array returned by the useState is the state which simply stores the information. The type of this state is any, which means; we can set any data type like string, number, array, object, etc.
The second element of the array is the function to update the count state. For now, we have set the function name as setCount, but it is not necessary to use this form as the name of the function. We could use anything like updateCount, but as a global convention, we named it as setCount, which means by name that it will work as setState for the count state. It is the replacement of the setState function we used to use in the class base component to update the state.
Here comes the last part of initializing the state, as we have passed 10 as a parameter of the useState function. This works as a default value of the count state. It is not necessary to pass a default value. If we declare a state but want the value to be undefined or be defined later, we can simply pass nothing to this function like below.
const [count, setCount] = useState();
Now, the initial value of the count state is undefined, and we can assign a value to this state by using the setCount function later.
Let’s see an implementation of these hooks in our application.
We imported useState hook from react library and declared a state named Count with an initial
value of 10.
The value of the count state is displayed in a <p> tag, which initially displays 10. Unlike classComponent, we don’t have to use this.count to display the state value; rather, we can simply call the state count just like a variable.
There are two buttons that have an onClick listener. By clicking those two buttons, we are gonna update the value of the count state. The setCount takes a parameter which is basically the updated value of the count state. In our case, we are just increasing or decreasing the value of the state by 1.
Now, let’s have an example of the same implementation in our classComponent.
So, without any doubt, it helps to increase the readability of the code and also enables us to write less code. It has some performance-enhancing factors too, which we will be discussing later in this article.
Implementing side effects or React lifecycle
As we all know, A React application is all about its components. So, the life cycle of ReactJs indicates the life cycle of its component. In our classComponent we used to use different life cycle methods for various side effects during a life cycle of a component such as:
These three were the basic life cycle methods of ReactJs in the class-based component, which used to be executed in different phases of the life cycle of a component. We could get this method only in classComponent, which was exported from the component class of React library and was available only in classComponent. The functional component was used as a presentational or dumb component previously.
When ReactHooks was launched, the usage of the lifecycle and implementation of side effects of a component went through a massive revolution. Now, functional components are not dumb anymore as they gained their freedom with the help of a ReactHooks named useEffect.
This single hook can support various lifecycle methods with slight changes. Their phases of react component (mounting, updating, and unmounting) can be captured with this single function or hook. Let’s have a look.
Basic implementation of useEffect is like bellow:
Just like our useState hook, useEffect is also exported from the react library, and we will import the hook in a similar way to useState. An useEffect consists of two parts:
1. A callback function
2. A dependency array
While declaring useEffect, we need to declare these two parts. Now, we will dive deep into this hook.
A callback function: This function contains all the necessary code that we want to execute in different phases of the life cycle.
A dependency array: This is a very interesting part of the hook. Depending on these array values, the hook will be executed. This dependency array takes elements such as a state. So, whenever any of the values of the array elements is updated, the useEffect will execute. We can pass an empty array as well, which means something different too. Don’t worry; we are coming to that point a bit later. But, we can also implement the useEffect hook without an array as well, and it will not create any error, and the application will run too. But, it is not recommended; in fact, let’s consider it as prohibited because it can cause infinite loop or infinite times of re-rendering of the component. We will discuss that later.
Now, we are gonna see how we can relate this component with previous lifecycle methods.
Let’s consider that we will simply do a console.log() of a different phase of the life cycle.
As we know, componentDidMount is executed when the updating phase of the React component is done. That means, when the component is rendered successfully, it will automatically execute the componentDidMount method. Now, we can achieve this using the useEffect hook with a simpler look.
Previously, we had to write a function named componentDidMount for this functionality.
Now, let’s see what it looks like in hooks:
First of all, any useEffect will work as a componentDidMount. That means all the useEffect hooks we declare within our component will execute after the component is rendered for the first time.
Here, both of the useEffect will print the console.log() after the first render is done. So for componentDidMount functionality, we will declare a useEffect() and write all necessary code inside the callback function that we want to execute when the component is first rendered.
After the mounting phase is done, here comes the updating phase of a component. When there will be some update to any of the states of a component, this phase occurs, and we can do some sideEffects during this phase. Previously, we used to use a different method named componentDidMount to achieve this.
It was the basic implementation of the method. So whenever any state is updated, this function will execute. It seems easy, right? There are some drawbacks:
So, it doesn’t matter which state is updated, this function will execute, and all the functionalities we write inside this function will run too. But that’s a bit awkward because, in most of the cases, we just need some specific functionalities depending on a specific state to be executed. That means, for different updates, we need different functionality. So, it is not performance-friendly to execute all the functionality for any of the state changes.
So this method has some problems which are solved by the useEffect hook. Let’s see what it looks like:
To demonstrate this feature, let’s consider a new state called money along with our previous count state.
Now, we will update these two-state from two different button clicks, and we want to do two different console.log(). That means whenever an update of the state is done, we will call our componentDidMount in a useEffect way, but for a different state, there will be different console.log()
So what we can do here is, we can have two useEffect. In the callback functions, we will declare the different functionalities we need. Now, the tricky part is the dependency array. So, the useEffect will execute only when the element of the dependency array is changed. For the two different useEffect, we will use two different dependencies. One is Count, and another one is money.
Now, when the count state is updated, only the first useEffect will run, and the console will price Count is updated.
The same goes for the money state as well. When the money state is updated, the second useEffect will be executed.
If we need to execute some functionality to be executed if any of the states are changed like our componentDidUpdate method, we can achieve that too. In that case, we will have to pass two states as elements of the dependency array.
So, we can see that hooks allow us to be precise about what functionality we want to achieve. It helps us to write less code. There are some performance enhancers here as well, which we will discuss a bit later.
When we are about to unmount a component from the dom, in the class-based component, if we wanted to execute a code block, we had a method called componentWillUnmount. This used to execute just before the component vanished from our dom. We can do this in react hooks too.
In every useEffect, we can pass a return function. This return function will be called on component unmount.
Here in the example, when the CountComponent is about to be unmounted, the return function of this useEffect will run, and there will be a console.log() with a message Component will unmount.
So, this was the basic implementation of Component Lifecycle methods in ReactHooks. As far as we have discussed, we can see the implementation of the two motivations of React Hooks, which are readability and less code. These hooks have a tremendous influence on the current popularity of ReactJs. Hence, we still have one more motivation to discuss React Hooks. So let’s discuss how hooks are helping to enhance performance.
React Hooks as Performance Enhancer
As ReactJs is a library for building interactive UI for an application, it is too obvious that performance is a vital concern, and ReactHooks also has many aspects of improving the performance of an application.
First of all, as we can see, we are using a functional component in React Hooks and can achieve all the functionality of classComponent effectively, so we no longer need to use class-based components. Now, it can be a question that, all through our journey towards programming, we always talk about object-oriented programming. So how is the functional component better than the class component when it comes to React? Isn’t it contradictory with OOP?
Well, it’s not. When we were using a class component to build a component, we used to extend a class, named Component from React, and all the life cycle methods were being initiated at the beginning of the initialization of the component regardless of our need. So if we just want to use componentDidMount, we have to initialize the compoentDidMount and componentWillMount too. In fact, if we don’t need any of the lifecycle methods and only require the state; we will have to load those lifecycle methods too.
Which is a big concern in terms of performance as while we will use Babel to ECMAScript 2015+ to backward-compatible version so that our browsers can understand and read, the size of webpack chunks is significantly bigger in classComponent than functional component. Because of, in-class component, we will convert some functionalities and methods which we don’t even need.
Let’s see our count application in two different ways to calculate the payload size after building the app.
Functional Component Build Size
Class Component Build Size
Here you can see, the main chunk of the build is less in functional components than class components. You may think that the size it reduces is not that significant but think if only for a small component, the difference is 80 bytes; what will happen if the application is very large. Also, we know, the more our payload size of JS, the longer time we will need to render it in our browser. So definitely, the functional component will enhance the performance in a significant way.
Secondly, React Hooks has introduced some advanced hooks as well, which can boost performance.
By using these advanced and custom hooks, the performance will be far better than the usual class-based component; among all of them, customHook is a revolutionary technique that will increase the reusability of our components and functionalities like API calls, custom utility functions, etc.
Using hooks is very helpful to improve the code and performance of the app, and it is advised to all react developers to start using ReactHooks as class components are about to be obsolete. In modern days, all new applications of ReactJs are being written in Hooks, and most of the old applications are also being converted to ReactHooks too due to the features and helpful functionalities of ReactHooks.
While it’s certainly not a complete reference of ReactHooks, I hope you will get a brief understanding of the Usage of Basic React Hooks and will help you to use ReactHooks in a proper way in your application. Feel free to leave a comment if you have any questions, suggestions, or anything else!