Husnain Mustafa
Posted on June 15, 2023
What are hooks?
Hooks are the functions which provides you to access capabilities of class components in your functional components.
For example, in class component you can make a component stateful, which is not possible in functional components without hooks.
Furthermore, you can define the actions which are required to be fired at specific point in the lifecycle of component. This was only possible in class components, and not in functional component, until hooks were introduced
Hooks were introduced in React 16.8.
Hooks provided by React
There are many many hooks that are provided by react. Some of them are:
useEffect
useState
useRef
useMemo
useCallback
useContext
useReducer
useLayoutEffect
For this tutorial, we are going through only the first five (useEffect, useState, useRef, useMemo, useCallback)
useEffect
useEffect lets you fire a desired action, i.e code execution, at some specific stages of component lifecycle.
But why would we need to fire a desired action at some specific stages of component lifecycle?
Example of firing an action
Well, let's consider a situation where you and your colleague are working on a project, lets say an eCommerce website. Your colleague is working on the front end and make a button which, when clicked, opens a Paypal dialog where user enters credentials and place an order. But the problem is, your colleague does not know how to integrate Paypal's api with eCommerce website. So he asks you to integrate Paypal's api. Along this, he also provides you a function, in which you are required to do all the tasks related to integrating Paypal's api.
To understand useEffect, we first need to understand the lifecycle of component in React.
There are 3 stages of component lifecycle which are as follows:
Component Mount, i.e the component gets rendered.
Component Update, i.e the component gets updated.
Component Unmount, i.e the component gets removed from the DOM.
We can fire an action at any of these 3 stages of lifecycle through useEffect.
How to implement useEffect
UseEffect takes 2 parameter, first one is the function which will get fired, and second one is the dependency array. Dependency array consists of variables which, when gets updated, causes our function to get fired. You will understand better by going through the codes below:
- Component Mount:
....
....
function myComponent(){
useEffect(()=>{
//Fire an action
}, [])
}
....
....
You can see the we left the second argument as an empty array. When we keep the dependency array (second argument) empty, we let React know that this we need to fire our desired action, function provided as first argument, when our components get mounted upon.
This case is same as below code in class component:
....
....
class myComponent extends Component{
componentDidMount(){
//Fire an action
}
}
....
....
Let's move on to second case, i.e, Component Update:
....
....
function myComponent(){
useEffect(()=>{
//Fire an action
}, [variable_1, variable_2])
}
....
....
In this case, we can see that code is almost same as before, but we have given 2 variables, variable_1 and variable_2, as dependency array. This lets React know that we want to fire our desired action whenever react find a change in any of these 2 variables. These variables are mostly the states of the components which will be explained later.
Class Component will implement same thing by:
....
....
class myComponent extends Component{
componentDidUpdate(){
//Fire an action
}
}
....
....
Let's move on to third case, i.e, Component Unmount:
....
....
function myComponent(){
useEffect(()=>{
return ()=>{
//Fire an action
}
}, [])
}
....
....
In this case, we can see that code is almost same as case one, but instead of firing our desired action in the function provided as first component, we are firing our action in the function that we are returning.
Class Component will implement same thing by:
....
....
class myComponent extends Component{
componentDidUnmount(){
//Fire an action
}
}
....
....
We can also have a combination of mounting and unmounting action in the same useEffect by:
....
....
function myComponent(){
useEffect(()=>{
//Firing an action at mounting
return ()=>{
//Fire an action at unmounting
}
}, [])
}
....
....
useState
States are use to store the data which can be used over time and can be updated as desired.
How are states different than variables?
General variables in react, like let myvar = 10
, get re initialized whenever a component re renders. Components get re renders whenever its state or props gets changed.
So let's consider we have parent component which passes prop, 'color', to the child component. This 'color' is used by child as font color. And we got a button with label, 'change color' which changes color to random one.
And in child component we, we need to keep the track about how many times color got changed, i.e, user clicked the 'change color' button.
If we use general variable like, let count = 0
and increment it every time user click on the 'change color', count will always be zero. Why? because every time user clicks 'change color', our component get re renders, as prop 'color' got change. So how can we store the count? We will use the state. States keep the data stored even if component gets re rendered.
How to implement useState
useState is easy to understand and use. useState is a function which takes one argument, the initial value of state, and return an array, which has state value at first index and a setter function to update the state value at second index. We do not update the value of state directly, if we do so, React does not consider that update and hence does not re renders the component. So we update the state value through the setter function provided by useState. Below is the code to understand it better:
....
....
const [count, setCount] = useSate(0)
....
....
useRef
useRef is somewhat same as useState, but instead of storing the value, it stores the reference of the element in the DOM. It is useful in making uncontrolled inputs, explained later.
Below is the code to implement useRef:
....
....
const ageRef = useRef(null)
....
....
return(
...
<input ref = {ageRef} />
...
)
....
....
You can fetch the element anywhere in the component by:
ageRef.current
What are controlled and uncontrolled inputs
Controlled inputs are the ones whose values are 'controlled' by the React states. We assign the value of input as the state and we update the state in the onChange method call. Below code would help you understand better.
....
const [age, setAge] = useState(null)
...
<input value = {age} onChange = {(event)=>{event.target.value}} />
...
....
Controlled inputs are better when we need to validate our input or when our input can cause the changes in DOM, for example, when typing age input as 13, we show the user the balloons on the screen.
Uncontrolled Inputs are inputs when we do not assign the value of input as state. Here we usually implement useRef to fetch the value of input.
....
const age = useRef(null)
...
<input ref = {age}/>
...
....
We can retrieve the value of input by:
age.current.value
useMemo
useMemo is used to store the returned value of the function. It is useful when got a high computational function. So if our component gets re rendered, we do not need to re call this function as we already have the returned value stored, unless variables in dependency array changes.
....
....
const age = useMemo(()=>{
//Doing some expensive function
....
....
return age
}, [var_1, var_2])
....
....
useCallback
useCallback is similar to useMemo, but instead of storing the value returned by function, we store the function itself, so that it does not get re defined/re initialized when the component gets re rendered.
It is useful in a case when we pass the function to the child component as prop. So whenever the parent component get re rendered, function get re defined/re initialized, reference to the function got changed, hence child also gets re rendered.
To avoid this, we can implement useCallback which stores the function and do not re initialize it unless the variables in dependency array gets changed.
Below is the code for implementing useCallback:
....
....
const calculateAge = useCallback(()=>{
//Tasks to calculate age
}, [var_1, var_2])
....
....
Both useMemo and useCallback can help optimize the performance of your React components by memorizing values or functions, respectively, and preventing unnecessary re renders.
That's all. Hope it would help.
Posted on June 15, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.