React Hooks Demystified

Tomas Nilsson
JavaScript in Plain English
4 min readSep 21, 2021

--

Photo by Christopher Gower on Unsplash

React Hooks is really cool, but it’s not a matter of magic. This article will go through the basics and hopefully make some things clearer.

What is a hook, anyway?

Well, to explain that it’s much simpler to compare to something that’s known. So, a typical component returns JSX as in this example:

import React from 'react';const Comp1 = (): JSX.Element => {
return <h1>The time is {new Date().toISOString()}</h1>;
};
export default Comp1;

So what about hooks? Well they return variables and functions rather than JSX.

A compontent returns JSX and a a hook returns (one or more) functions, variables or objects.

OK, seems easy. But why not use a module then? Something like:

export function Sum(number1: number, number2: number): number { 
return number1 + number2;
};

Because modules cannot “interact” with React; hooks are built to access React features such as useState . Read more about this at the very end of the article.

Now, let’s dive into some examples.

Hook example — useCounter

Consider the follwoing code. It returns a number and a function (named “increment”).

import React from 'react';const useCounter = (): [number, () => void] => {     const [number, setNumber] = React.useState(0);     function increment() {
setNumber(randomNumber => randomNumber + 1);
}
return [number, increment];};export default useCounter;

The entire code to use it is:

import React from 'react';
import useCounter from './usecounter';
function Hook1Example() { // Grab the number and the increment-function
const [number, inc] = useCounter();
return <>
Number: {number}
<button onClick={inc}>Increment</button>
</>
}export default Hook1Example;

In their most simple example, hooks are basically just this.

Hook example — useIsWeekEnd

The number of parameters returned from a hook can be arbitrary and the way parameters are returned can also be changed. Let's show it with examples:

As an Array:

…in this case, as a number and a function.

import React from 'react';const useCounter = (): [number, () => void] => {    const [number, setNumber] = React.useState(0);    function increment() {
setNumber(randomNumber => randomNumber + 1);
}
return [number, increment];};export default useCounter;

As a single item:

… in this case, a boolean:

import React from 'react';const useIsWeekend = (): boolean => {   const [isWeekEnd, setIsWeekEnd] = React.useState<boolean>(false);   React.useEffect(() => {
setIsWeekEnd([6, 0].includes(new Date().getDay()))
}, []);
return isWeekEnd;};export default useIsWeekend;

As an object:

…perfect for destructuring :)

import React from 'react';const useCalculator = (): { result: number; Add: (i: number) => void; Set: (i: number) => void; } => {const [result, setResult] = React.useState(0);     function Add(i: number) {
setResult(result => result + i);
}
function Set(i: number) {
setResult(result);
}
return { result, Add, Set }};export default useCalculator;

And the component:

import React from 'react';
import useCalculator from './usecalculator';
function Hook2() { const { result, Add, Set } = useCalculator() return <>
Result: {result}<br />
<button onClick={() => Add(1)}>Increment</button>
<button onClick={() => Add(-1)}>Decrement</button>
<button onClick={() => Set(0)}>Reset</button>
</>
}export default Hook2;

Hook Example — useIsLucky

As with components, a hook may trigger a rerender. Conside the following example:

import React from 'react';const useIsLucky = (userID: string): [boolean | undefined] => {    const [isLucky, setIsLucky] = React.useState<boolean | undefined>(undefined);   React.useEffect(() => {         // Fake a call to the API where the user
// is checked if they're lucky
setTimeout(() => {
setIsLucky(Math.random() > 0.5)
}, 1000);
}, [userID]); return [isLucky];};export default useIsLucky;

And the component:

import React from 'react';
import useIsLucky from './useislucky';
function Example5() { const [result] = useIsLucky("Tomas"); if (result !== undefined)
return <>Was lucky? {result ? "Yes" : "No"}</>
else
return <>Loading..</>
}export default Example5;

Functions vs Hooks!

Alright, the basics of hooks are covered. But before letting go, there’s one more thing that needs to be covered:

When should hooks be used and when should ordinary modules (eg, .ts-files with code) be used?

Well, it boils down to the dependency of React. Consider the following code where no dependencies for React can be found. Alright, it’s named useSumHook, but in reality, it’s not a hook.

const useSumHook = (number1: number, number2: number): number => {
return number1+number2;
};
export default useSumHook;

Me personally, I’d store this function in a .ts-file as:

export function Sum(number1: number, number2: number): number { 
return number1 + number2;
};

and then use it as:

import { Sum } from './misc';

Git repo

It’s not pretty, but it’s useful. https://github.com/tomnil/hooksexample

Enjoy :)

More content at plainenglish.io

--

--