A Comprehensive Guide To React Hooks For Beginners
As someone new to React, it can be overwhelming to figure out how to use various tools. Despite becoming comfortable with a couple of hooks like useState
and useEffect
, it still took me a while to grasp the usage of other React hooks. Perhaps you’re also unfamiliar with how to use React hooks, this article will assist you in comprehending the concept more quickly.
Prerequisites
Before we dive into React Hooks, it’s important to have a basic understanding of React components and JSX syntax. If you’re not familiar with these concepts, it might be helpful to take a beginner-level course or tutorial before continuing.
It’s also helpful to have a basic understanding of JavaScript, particularly the ES6 syntax and concepts such as arrow functions, classes, and destructuring.
What are React Hooks?
If I had to describe React hooks, I would say they handle various tasks within components such as managing state, global state, side effects, and component functionalities. A state is used to store values that may change from their initial value and can hold different data types such as integers, booleans, arrays, objects, and more. When the state of a component changes, React automatically re-renders the component and updates the user interface to reflect the new state.
Hooks enable developers to reuse stateful logic across different components, resulting in more concise and reusable code. Overall, React Hooks make it easier for developers to build and maintain scalable and flexible React applications.
There are several types of Hooks, each serving a different purpose, and they provide a way to reuse stateful logic between components without the need for inheritance.
Types of React Hooks
- UseState —State
- UseEffect — Side Effects
- Use Context — Context API
- Use Reducer — Reducers
- UseRef
- Use Memo
- Use CallBack
- Custom Hooks — customized
The UseState Hook
The useState
Hook is used to manage the state in functional components. It takes an initial state value as a parameter and returns an array with two values: the current state value and a function to update the state.
Example of how to use useState
to manage a counter:
//import usestate from react
import React, { useState } from 'react';
function Counter() {
// count is the intial state, useState holds the initial value
// setCount is the updated state that holds the updated value
const [count, setCount] = useState(0);
function handleIncrement() {
setCount(count + 1);
}
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
In this example, we use the useState
Hook to manage the count state. We define the initial state value as 0 and use the setCount function to update the state when the button is clicked.
The UseEffect Hook
The useEffect
Hook is used to perform side effects in functional components. Side effects can include fetching data from an API, manipulating the DOM. The useEffect Hook takes a function as a parameter and executes it after the component has rendered i.e useEffect
is called after every render.
To conditionally run an effect, we specify a second parameter to useEffect
. The second parameter is the array of values that the effect depends on.
Example of how to use useEffec
t to update DOM(title):The document title is updated as the useState value updates(number) i.e clicking on the IncreaseNumber button also updates the DOM element(title)
// import useEffect from 'react'
//The useState handles the state (number)
// The effect depends on the state value(number), we passed this as the second parameter
import React, { useEffect, useState } from "react";
const UseEffect = () => {
const [number, setNumber] = useState(0);
useEffect(() => {
document.title = `You clicked ${number} times`;
}, [number]);
return (
<div>
<button
onClick={() => {
setNumber(number + 1);
}}
>
IncreaseNumber
</button>
</div>
);
};
export default UseEffect;
In this example, we use useState
Hook to handle the number state. And useEffect
to update the DOM element , this renders whenever the number state updates i.e it rendering depends on the state(number), this will be the second parameter ,the array value.
Using useEffect to fetch API data using JSON placeholder
import React, { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(data => setData(data));
}, []);
return (
<div>
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
The UseContext Hook
To understand the usage of UseContext
well, we consider a React App that have many components i.e components and in components. If these components then needs to access the same data across the application, we make use of useContext
hook for easy consumption of the data. This provides a way to pass data through the component tree without having to pass it down manually on every level.
Steps in Creating Context
Step 1 — Create Context in App.js
export const UserContext = React.createContext();
Step2 — Provide context with a value to be available. The child/children component must be enclosed in the provider, for the value to be available.
<MyContext.Provider value="Victoria">
<MyComponent />
</MyContext.Provider>
Step3 — We then use the useContext
hook: Used in Mycomponent.js to consume the value.
(i) Import useContext
(ii) Import the UserContext
from App.js
(iii) Call the useContext
function. It takes the context as an argument and returns the current value of the context.
import React, { useContext } from "react";
import {UserContext} from ./App
const MyComponent=() => {
const username = useContext (UserContext);
return (
<div>
{username}
</div>
);
}
When the MyComponent
component is rendered, it will display the value "Victoria", which was passed down through the context from the App
component. If we had multiple components that needed access to the same data, we could pass the value down through the context once and then have all the components consume it using the useContext
hook.
The useReducer Hook
useReducer
is a hook used for state management , more structured and predictable way than using the useState
. This hook works in comparism the reduce()
method in JavaScript, both involve reducing an array of values to a single value/ a pair of values. The useReducer
hook returns a pair of values using array distructuring syntax, similar to useState
.
The useReducer
hook takes in two arguments: a reducer function and an initial state. The reducer function is responsible for handling state updates and returning a new state. It takes in two arguments: the current state and an action object that describes what kind of update needs to be performed.
useReducer(reducer, initialState)
newState= reducer(currentState, action)
The useReducer
hook returns a pair (array) of values: the current state and a dispatch function. The dispatch function is used to trigger state updates and takes in an action object as its argument. When the dispatch function is called, React will call the reducer function with the current state and the action object, and then use the return value as the new state .dispatch allows us to execute a code corresponding to a particular action.
useReducer= const [currentState, dispatch]
//Recall useReducer takes two arguments
const [currentState, dispatch] = useReducer(reducer, initialState)
Now, we want to see how we can use useReducer
hook to create a counter App.
Step 1 — Import useReducer from react
Step 2 — Defining the initial state and reducer function
Step 3 — Get value to display and call the useReducer function. Dispatch allows us to execute a code corresponding to a particular action.
Below is what the code look like following the steps:
//Import useReducers from React
import React, { useReducer } from "react";
// Define the initial state
const initialState = 0;
// defining reducer function
const reducer = (state, action) => {
switch (action) {
case "increment":
return state + 1;
case "decrement":
return state - 1;
case "reset":
return initialState;
default:
return state;
}
};
const UseReducer = () => {
// call the useReducer function
const [count, dispatch] = useReducer(reducer, initialState);
return (
// display the counter app, using dispatch to execute the action.
<div>
<div>{count}</div>
<button
type="button"
onClick={() => {
dispatch("decrement");
}}
>
Decrement
</button>
<button
type="button"
onClick={() => {
dispatch("reset");
}}
>
Reset
</button>
<button
type="button"
onClick={() => {
dispatch("increment");
}}
>
Increment
</button>
</div>
);
};
export default UseReducer;
In this example, we define a reducer function that takes in the current state and an action object. The action object has a type property that describes what kind of update needs to be performed. In this case, we’re defining three actions: increment, decrement and reset, which will increase , decrease and reset the count respectively.
We then define a component that uses the useReducer
hook to manage the state of our count variable. We pass in the reducer function and the initial state declared (initialState=0) as arguments to the useReducer
hook.
The Counter component then returns a JSX template that displays the current count and three buttons that use the dispatch function to trigger state updates. When the dispatch function is called with an action object, React will call our reducer function with the current state and the action object and use the return value as the new state.
Other ways to use useReducer
hook in your application includes:
- Using
UseReducer
to maintain both state and action as objects - We can use
UseReducer
anduseContext
for global state management - Fetching Data using
useReducer
Hook.
I have all these examples in my GitHub repo that will be attached to the end of this article.
The useRef Hook
The useRef
hook makes it possible to access DOM elements directly or to store mutable values that persist across renders(within effect). The useRef
hook takes an initial value as its argument and returns a mutable ref object with a current property.
This code example demonstrates how to use the useRef
hook in conjunction with the useEffect
hook to focus an input element when a component is mounted.
import React, { useEffect, useRef } from "react";
const UseRefHook = () => {
const inputRef = useRef(null);
useEffect(() => {
//focus the input element
inputRef.current.focus();
}, []);
return (
<div>
<p>Using useRef for input focus</p>
<input ref={inputRef} type="text" />
</div>
);
};
export default UseRefHook;
In this example, we define a functional component called UseRefHook
. Inside the component, we create a ref using the useRef
hook and assign it to the inputRef variable. We then use the useEffect
hook to call a function that focuses on the input element using the current property of the inputRef object. The second argument to the useEffect
hook is an empty array [], which ensures that the effect runs only once, when the component mounts.
Finally, we return some JSX that includes a paragraph element and an input element that uses the inputRef reference.
By using useRef
in conjunction with useEffect
, we can ensure that the input element is focused when the component is first mounted. This can be particularly useful in cases where the input element is a crucial part of the user experience, such as in a search box or a login form.
UseMemo and UseCallback hooks
useMemo
and useCallback
are two hooks in React that are used for performance optimization. Both of these hooks are used to memoize or cache the results of an expensive computation, so that the computation does not need to be repeated every time a component re-renders. However, they are used in slightly different contexts.
The useMemo
hook is used to memoize the result of a function call. It takes two arguments - a function and an array of dependencies. The function is the expensive computation that we want to memoize, and the dependencies are the values that the function depends on. React will re-run the function and recompute the result only when any of the dependencies change.
import React, { useState, useMemo } from "react";
const MemoHook = () => {
const [counterOne, setCounterOne] = useState(0);
const [counterTwo, setCounterTwo] = useState(0);
const IncrementOne = () => {
setCounterOne(counterOne + 1);
};
const IncrementTwo = () => {
setCounterTwo(counterTwo + 1);
};
const Even = useMemo(() => {
let i = 0;
while (i < 2000000) i++;
return counterOne % 2 === 0;
}, [counterOne]);
return (
<div>
<div>
<h1>Using MemoHook</h1>
<button onClick={IncrementOne}> Counter-One {counterOne}-</button>
<span>{Even() ? "Even" : "odd"}</span>
</div>
<div>
{" "}
<button onClick={IncrementTwo}>Count-Two {counterTwo}</button>
</div>
</div>
);
};
export default MemoHook;
In the given code, useMemo
is used to memoize the result of a function that checks if the counterOne
value is even or odd. The function is called Even
and it's defined inside the component. The function uses a loop to delay the execution, which simulates an expensive computation.
The second argument of useMemo
is an array of dependencies, which tells React to recompute the memoized value whenever any of the dependencies change. In this case, the only dependency is counterOne
, so the memoized value will only be recomputed when counterOne
changes.
The memoized value is then used in the JSX to display “Even” or “odd” depending on the value of counterOne
. This means that the expensive computation of Even
only happens when counterOne
changes, and not on every render of the component.
The useCallback
will return a memoized version of the callback version that only changes if one of the dependencies has changed.
To catch function — useCallback
To catch result — useMemo
The Custom Hooks
Custom hook simply means a customized way of creating reusable logic. A custom hook is a function that uses one or more built-in React hooks (such as useState, useEffect, useContext, etc.) and returns stateful data and functions that can be used by other components.
How To Create and use a Custom Hook
Creating a Custom Hook
Step 1 — Identify the reusable logic: Determine what code can be extracted into a separate function to make it reusable across components.
Step 2 — Create a new function : The function name must start with use
(keyword used to represent an hook) that will hold the reusable logic. This function should use one or more built-in React hooks, this is the custom hook.
Step 3 — Define the hook’s return value: Determine what data or functions should be returned from the hook.
Step 4 — Export the custom hook: Export the new function as a custom hook.
Example: Counter App CustomHook
import { useState } from "react";
//using useCounter hook instead of repeating the same code for components
//reusable logic
//Hook named useCounter
const useCounter = (initialCount = 0, value) => {
const [count, setCount] = useState(initialCount);
const decrement = () => {
setCount((prevCount) => prevCount - value);
};
const increment = () => {
setCount((prevCount) => prevCount + value);
};
const reset = () => {
setCount(0);
};
//we return an array of values: count, inc, dec, and reset
return [count, increment, decrement, reset];
};
//export useCustom
export default useCounter;
Using a custom hook
- Import the custom hook: Import the custom hook into the component where it will be used.
- Call the custom hook: Call the custom hook inside the component. This will return the data or functions that were defined in the hook.
- Use the returned values: Use the returned data or functions in the component as needed.
import React from "react";
// import the custom hook
import useCounter from "./useCounter";
const CustomHooksComponent1 = () => {
//use the custom hook and its logics in the component
const [count, increment, decrement, reset] = useCounter(10, 2);
return (
<div>
CustomHooksComponent1
<div>
<p>CustomHook1- {count}</p>
<button onClick={decrement}>Decrement</button>
<button onClick={increment}>Increment</button>
<button onClick={reset}>Reset</button>
</div>
</div>
);
};
export default CustomHooksComponent1;
The useCounter
hook takes two arguments, an initial count value of 10
and a step value of 2
, and returns an array containing the current count value, a function to increment the count, a function to decrement the count, and a function to reset the count to its initial value.
The component then uses these values to render a simple counter UI with three buttons to increment, decrement, and reset the count value. When the user clicks on one of these buttons, the corresponding function from the useCounter
hook is called to update the count state and re-render the component with the new count value.
Overall, this component demonstrates how a custom hook can be used to encapsulate complex state logic and make it reusable across multiple components. By using the useCounter
hook, the CustomHooksComponent1
component can manage its own count state without having to write any custom state management code.
Conclusion
React hooks are a powerful and flexible feature that allows developers to write more modular and reusable code in their React applications. Whether you need to manage component state, fetch data from an API, or interact with the browser DOM, there is likely a hook that can help you accomplish your task more efficiently.
While it can take some time to get comfortable with the different types of hooks and their various use cases, the benefits of using hooks can be substantial, including improved code readability, easier debugging, and faster development times.
Final Piece
If you’re interested in learning more about React hooks and how they work in practice, you’re in luck! I’ve put together a comprehensive Github repository that includes code examples for all the most important React hooks to help you understand how they work.
It’s such a long one right? Yea! we just covered all the React Hooks.
Thank you for taking the time to read this article. I hope that it has given you a better understanding of how to use React hooks effectively in your own projects.