React.JS Hooks Made Easy

Robert Y-Squared
6 min readNov 17, 2022

--

1 INTRODUCTION

2 BASIC HOOKS

2.1 useState

2.2 useEffect

2.3 useContext

3 ADDITIONAL HOOKS

3.1 useReducer

3.2 useRef

3.3 useCallback

3.4 useMemo

4 CUSTOM HOOKS

5 GITHUB, CONTACT & SOCIALS

1 INTRODUCTION

What is a React Hook ? Essentially a hook is just a JavaScript function that allows us to manage state and side effects inside a functional component.

In React, functional components are easy to use but do not have access to state or lifecycle methods natively.

Before 2018 you could only manage the state using a class component. Class components allow you to utilize state and lifecycle methods by default. In a class component you can declare a state by setting it to an object, use props to declare the initial state and then change the state using lifecycle methods.

This can be quite messy, that’s where hooks come in, they allow us to access all the functionality of classes in a streamlined manner inside functional components.

There are many built in React hooks, in this article we will look at the three basic hooks and a few additional ones. We will also take a look at how to build our own. For the full list of the hooks, you can check them out in the official React documentation ( https://reactjs.org/docs/hooks-reference.html )

2 BASIC HOOKS

2.1 useState

The useState hook manages states, it takes an argument and a function. The argument is the initial state and a function to update the state.

In the below example, 0 is the initial state of the count, and setCount is the function that will update it. When we click on the button it will then change the of the {count} and render it on the DOM.

Example:

import { useState } from "react";
function useStateEx() {
const [count, setCount] = useState(0);
return (
<div>
<h1>useStateEx</h1>
<p>My Counter: {count}!</p>
<button type="button" onClick={() => setCount(count + 1)}>
Increment counter
</button>
</div>
);
}
export default useStateEx;

2.2 useEffect

The useEffect hook manages side-effects like API calls, timers, mutations and so on!

useEffect accepts two arguments, a function and a dependency. The dependency is optional.

In the below example we’ve added an alert with useEffect it will be triggered when the page renders but generally this would be used for loading API’s.

If we wanted to stop useEffect running on mount we would use it in combination with the useRef hook to do so and then if we only wanted the useEffect to trigger on a state change we would add the variable or function name into the dependency array.

Example:

import { useEffect, useState } from "react";
function useEffectEx() {
const [count, setCount] = useState(0);
useEffect(() => {
alert("Hello! I am an alert box!");
}, [ ]);
return (
<div>
<h1>useEffectEx</h1>
<p> {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment count with Alert
</button>
</div>
);
}
export default useEffectEx;

2.3 useContext

The useContext hook creates common data that can be accessed throughout the component hierarchy, basically, It’s a way to manage state globally!

useContext is a way to combat prop drilling which is the process of passing state through many nested components. This is messy and can get confusing !

In the below example we have three files to demonstrate useContext. First we create context in the component we want, this is usually done in a component higher up in the hierarchy, then we wrap the components we want the context to be available in with context provider tags.

To use the context we simply import it to the component files and call it with useContext!

Example:

useContextEx.js

import React, { useState, createContext } from "react";
import Log from "./Log";
import Name from "./Name";
export const AppContext = createContext(null);function useContextEx() {
const [name, setName] = useState("");
return (
<AppContext.Provider value={{ name, setName }}>
<h1>useContext</h1>
<Name /> <Log />
</AppContext.Provider>
);
}
export default useContextEx;

log.js

import React, { useContext } from "react";
import { AppContext } from "./useContextEx";
function Log() {
const { setName } = useContext(AppContext);
return (
<div>
<input
onChange={(event) => {
setName(event.target.value);
}}
/>
</div>
);
}
export default Log;

Name.js

import React, { useContext } from "react";
import { AppContext } from "./useContextEx";
function Name() {
const { name } = useContext(AppContext);
return (
<div>
<h2>Name: {name}</h2>
</div>
);
}
export default Name;

3 ADDITIONAL HOOKS

3.1 useReducer

useReducer is very similar to useState. We opt to use useReducer when we have complex state logic that has multiple values.

Instead of using a setter function we use dispatch. We then create a reducer function which is usually has a switch statement inside it with the state changing logic, then to set the initial state we create an object so we can take multiple values and access them using the dot notation.

Example:

import { useReducer } from "react";
const initialState = { count: 0 };function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
throw new Error();
}
}
function useReducerEx() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<h1>useReducerEx</h1>
<div>
<h2>Count: {state.count}</h2>
</div>
<button onClick={() => dispatch({ type: "decrement" })}>
decrement --
</button>
<button onClick={() => dispatch({ type: "increment" })}>
Increment ++
</button>
</div>
);
}
export default useReducerEx;

3.4 useRef

useRef allows us to do a few things, for instance accessing DOM elements directly. We add a ref attribute to the element we want to access! It’s also important to note that useRef allows us to store a mutable value that does not cause a re-render; it also persists the value between renders !

When we use useRef it returns an object called current, We also set the initial value to null or 0.

useRef can also be used to keep track of state changes.

Example:

import { useRef, useState } from "react";
function useRefEx() {
const inputRef = useRef(null);
const [name, setName] = useState("John Doe"); return (
<div>
<h1>{name}</h1>
<input type="text" placeholder="name" ref={inputRef} />
<button onClick={() => setName(inputRef.current.value)}>
Change Name
</button>
</div>
);
}
export default useRefEx;

3.3 useMemo

The use case for useMemo is optimization, by default when state changes in a component it re-renders, this also means functions inside will run again. If we have a large resource intensive function in the component it is inefficient to run it every time unless it is needed to do so.

To stop this we create a new variable which will be the name of the memoized function and set it equal to useMemo, we then call the resource intensive function inside it and set the dependency array so it will only run when relevant data changes. Wherever we were calling the original function in the component we now use the newVariable instead.

const newVariable = useMemo(() => resourceIntensiveFunction(data), [data]);

Note: Memoization is simply caching the value so that it does not need to be recalculated

3.4 useCallback

The useCallback and useMemo hook are very similar. The useMemo hook returns a memoized value and the useCallback returns a memoized function. The concept of isolating a resource intensive function to stop it from running again during a re-render remains the same!

const memoizedFunction = useCallback( () => {
resourceIntensiveFunction(data);
},
[data],
);

4 CUSTOM HOOKS

As mentioned before hooks are simply JavaScript functions that allow us to manage state and side effects in a functional component.

In the below example (Credit to w3schools) we are writing some logic in one component to create our custom hook, then we export it so we can use it elsewhere in our application. In this case we are creating a function that uses the built in javascript fetch function with some existing hooks to create a reusable hook that fetches data from APIs.

In the second code block we can see our hook being implemented and then rendering results as a list using .map.

useFetch.js

// This example was taken from https://www.w3schools.com/react/react_customhooks.asp
// Create our custom hookimport { useState, useEffect } from "react";const useFetch = (url) => {
const [data, setData] = useState(null);
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return [data];
};
export default useFetch;

customHook.js

// This example was taken from https://www.w3schools.com/react/react_customhooks.asp
// Call our custom hook
import useFetch from "./useFetch";function CustomHook() {
const [data] = useFetch("https://jsonplaceholder.typicode.com/todos");
return (
<>
<h1>customHook</h1>
{data &&
data.map((item) => {
return <p key={item.id}>{item.title}</p>;
})}
</>
);
}
export default CustomHook;

4 GITHUB, CONTACT & SOCIALS

Please contact us if you see any mistakes on this post, have any suggestions or business inquiries.

Original Article:

Please fill out the form on https://y-squared.com/contact or email us at team@y-squared.com.

The Author: This post was written by Robert from Y-Squared:

Click here to follow me on Github @Rob1818

Connect with me on LinkedIn

Blog Site:

https://y-squared.blog/

Medium: (Follow me on medium)

https://medium.com/@Robert-Y-Squared

Business Site: (Fill in the form if you have any business inquires)

https://y-squared.com/

GitHub Repo for this post:

https://github.com/Rob1818/blog-post-4-react-hooks-101

--

--