Lazy Panda

Developer

Posts
57
Comments
48
Likes
76
Posts
57
Comments
48
Likes
76
sidebar

React hooks explanation with an example using NextJs and TypeScript

React version 16.8 onwards, hooks are been introduced. React Hooks are functions and serve as a modular replacement for state and lifecycle methods. React Hooks are allowed to use on functional components. 

react hooks useState useRef forwardref explanation and example

 

Important Rules for React hooks - 

  • React hooks are built to be used in functional components.
  • One hook can call another hook.
  • Hooks should be declared at the top level of a component.
  • Hooks should not be called from nested conditions or functions, inside any loops.
  • Hooks should not be used in any class components.
  • The hook should not be called from any regular function.

Now, let's discuss what are the available react hooks and how we can use them properly in react application - 

 


useState React Hook explanation

useSate() hooks are used to initialize any variable as a state variable. 

import { useState } from "react";

 

const [stateVariable, setStateVariable] = useState(0);

 

  • if a component re-renders (not refresh the page), the state variable value will persist.
  • always update state variable value by calling setStateVariable() method. 
  • updating state variable value is asynchronous.
    • You do need to depend on useEffect() or useCallback() to get the most updated value of a state variable. (Examples are given in a later section)
  • declare all the state variables right after component declaration. 
  • always declare the state variable as const, do not use let for state variable.

 

Difference between state variable and class variable

  • In case of any update happens on the state variable, the respective components will rerender.
    • Whereas updation on the class variable will not have any impact on rerendering the component.
  • Any update on the state variable will execute the useEffect hook.
    • updation on the class variable will not execute any hooks.
  • In case of rerendering the component, the state variable will hold the previously updated value. 
    • Rerendering on a component, the class variable will be lost the previous value and initialize again with a default value.

(Example has been given in the bottom of the article)

 


useEffect React Hook explanation

useEffect hooks are been used to get a callback in case of any dependencies are being updated with new values. Such as -

// with no dependency

let count = 0;

const [stateCount, setStateCount] = useState(0);

 

useEffect(() => {

console.log('Execute all time, as there are no dependency');

count = 0;

console.log('class Variable (no dependency): ', count);

console.log('state Variable (no dependency): ', stateCount);

}, []);

 

// with dependency 

useEffect(() => {

/**

* This code will execute everytime - when we made any change on state variable

*/

console.log('state variable has updated');

console.log('state Variable (with state variable dependency): ', stateCount);

}, [stateCount]);

 

  1. If dependency has not been provided, the useEffect() hook will call every time while rendering / rerendering.
  2. if dependency is an empty array, like [], it will run once after initial rendering
  3. having multple dependency, [count, stateVariable, stateArrayVariable] will run whenever any of dependency gets updated.
  4. do not use async on useEffect hook declaration. 

const UseEffect = () => {

const [countries, setCountries] = useState<Array<any>>([]);

 

useEffect(() => {

const getAllCountries = async () => {

let allCountry = await fetch('https://restcountries.com/v3.1/all');

let response: Array<any> = await allCountry.json();

if (response) {

setCountries(response);

}

}

 

getAllCountries();

}, []);
 

return (

<Layout>

<Head>

<title>Next js useEffect explanation</title>

</Head>

<Container>

<div className="flex justify-between p-3">

<div className="w-1/2 border p-4">

<p className="underline underline-offset-4">API call using - useEffect</p>

<ul className="h-64 overflow-scroll">

{countries.map((country: any, index: number) => (

<li key={index}>{country?.name?.common}</li>

))}

</ul>

</div>

</div>

</Container>

</Layout>

);

}

 

export default UseEffect;

 

 

Prevent useEffect From Running Every Render

It will be required to add an array of dependencies, to prevent multiple time execution. Another way to think of this array: it should contain every variable that the effect function uses from the surrounding scope. So if it uses a prop? That goes in the array. If it uses a piece of state? That goes in the array.

 


useCallback and useMemo react hook explanation 

useCallback is used to optimize the rendering behavior of the react component. 

Example - I have a Parent component and one child component and while changing anything on the parent component rerender the Parent component and child component too. As we have not made any change on the child component, in that case rerendering on the child component is not good for performance. 

the memo is being used to memorize some expensive (complex) methods of execution. 

Example - Let's consider I am returning a factorial value of 5 if I use useMemo on the factorial method, the first time the method will execute, and next time onwards it will simply return the value instead of executing it until the parameters get changed. 

Let's see some examples on it. 

Parent Component

useCallback-hook-typescript-react-nextjs

Child Component

useMemo-memo-react-typescript-nextjs

 

In the above case, clicking on any of the Child Component values will only rerender the parent component.

 


useRef, forwardRef and useImperativeHandle explanation

useRef() hook - In a simple word, using useRef we can access the DOM element. 

But there are some more stuff we can do using useRefforwardRef and useImperativeHandle

  • If we use useRef() in the same component, using .current will give an option to update the value without doing and rerendering. 
  • If we use useRef() as a child component, we have had to leverage forwardRefuseImperativeHandle together, in order to access the parent component metadata to the child component.

Let's see an example - 

useRef, forwardRef, useImperativeHandle explanation

Here, I have useRef() on child component to pass the Register & Cancel button action to child compoent. 

  • I have a parent component - dropdown 
  • The parent component will have 2 buttons - clear & register
  • The child component is having few more fields 

By clicking on the Register button, submit action from the parent component will pass to the child component and handle the register method action. 

useRef, forwardRef, useImperativeHandle explanation

// Parent Compoent

// declaration & initialization

const employeeFormRef = useRef<IFormRef>(null);

 

// pass the call to child component

const submitEmployeeForm = (event: FormEvent<HTMLFormElement>) => {

if (employeeFormRef.current) {

employeeFormRef.current.submit();

}

 

event.preventDefault();

}

//pass ref as a props

<ChildForm ref={employeeFormRef} company={selectCompany} />

 


Demo: 


React hooks are very powerful for your functional component. Hooks will not work on the class component, rather they let you use React without classes. In sort - 

  • useMemo is to memoize a calculation result between a function's calls and between renders
  • useCallback is to memoize a callback itself (referential equality) between renders
  • useRef is to keep data between renders (updating does not fire re-rendering)
  • useState is to keep data between renders (updating will fire re-rendering)

Let me know about your thaught about hooks, you can add your comments below for improving the content if I missed anything. 

- LP