The Basics of React Hooks: A Comprehensive Guide - Part 1
useState , useEffect , useRef
React Hooks, introduced in React 16.8, have changed the way we write functional components in React applications. They allow us to use state and other React features without writing a class. This blog aims to demonstrate the most commonly used hooks: useState
, useEffect
, and useRef
, providing a foundation for building react applications.
TheuseState
Hook
Why Use State Instead of Normal javascript variable let or const
Reactivity: State variables are reactive. When state changes, React re-renders the component to reflect those changes. Normal variables don’t trigger re-renders.
Persistence: State persists between re-renders, while normal variables get reset.
Consistency: React ensures state consistency across re-renders, providing a reliable and predictable way to manage dynamic data.
import React, { useState } from 'react'; function ExampleComponent() { // Normal state update pattern const [countNormal, setCountNormal] = useState(0); // prevState-based state update pattern const [countPrevState, setCountPrevState] = useState(0); // Normal state update when clicking the "Click me (Normal)" button const handleNormalClick = () => { // Increment count by 1 setCountNormal(countNormal + 1); }; // prevState-based state update when clicking the "Click me (prevState)" button const handlePrevStateClick = () => { // Increment count by 1 based on previous state setCountPrevState((prevState) => prevState + 1); }; return ( <div> <div> <p>You clicked {countNormal} times (Normal)</p> <button onClick={handleNormalClick}> Click me (Normal) </button> </div> <div> <p>You clicked {countPrevState} times (prevState)</p> <button onClick={handlePrevStateClick}> Click me (prevState) </button> </div> </div> ); } export default ExampleComponent;
When you need to update a state based on its previous value, using
(prevState) => ...
is essential. This pattern ensures that your updates are dynamic and reflect the latest state, even in asynchronous or concurrent situations.
When you want to increment or decrement a value based on its current state, likesetCount((prevState) => prevState + 1)
orsetCount((prevState) => prevState - 1)
The
useEffect
HookuseEffect
is a built-in hook in React that allows you to perform side effects in function components. Side effects are operations that happen after or as a result of the main logic of your component, such as data fetching, DOM manipulation, or setting up subscriptions.
It serves as a replacement for lifecycle methods likecomponentDidMount
,componentDidUpdate
, andcomponentWillUnmount
in class components.When you don't provide a dependency array, the effect runs after every render. This is similar to
componentDidUpdate
in class components and is used for side effects that should run after each render.When you pass an empty dependency array, the effect runs only once after the initial render. This is equivalent to
componentDidMount
in class components and is used for one-time setup or data fetching.When you pass specific dependencies to
useEffect
, the effect will run whenever any of those dependencies change. This is useful for controlling when the effect should execute based on specific data changes
import React, { useState, useEffect } from 'react';
function ExampleComponent({ data }) {
const [count, setCount] = useState(0);
// Effect with specific dependencies
useEffect(() => {
// This code runs when 'data' changes
console.log('Data changed:', data);
}, [data]);
// Effect with empty dependency array (runs once)
useEffect(() => {
console.log('Component mounted (initial render)');
return () => {
console.log('Component unmounted');
};
}, []);
// Effect without a dependency array (runs after every render)
useEffect(() => {
console.log('Component re-rendered');
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
The return
statement in useEffect
is used to define a cleanup function that runs when the component unmounts or when the state value changes. This cleanup function is essential for tasks like clearing intervals, unsubscribing from subscriptions, or releasing resources to prevent memory leaks.
import React, { useState, useEffect } from 'react';
function TimerComponent() {
const [timer, setTimer] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setTimer((prevTimer) => prevTimer + 1);
}, 1000);
// Cleanup function to clear the interval
return () => {
clearInterval(intervalId);
};
}, []);
return <div>Timer: {timer} seconds</div>;
}
In this example, the return
statement is used to clear the interval created by setInterval
when the component unmounts. This ensures that there are no lingering intervals that could cause memory leaks
TheuseRef
Hook
useRef
hook in React allows you to create and manage references to DOM elements or to persist values across renders without causing re-renders. You can directly access the dom element.
Use useRef
when you need to directly manipulate DOM elements, such as focusing on an input field, measuring dimensions, or animating elements.
Don't use useRef
for managing component state that affect rendering.
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef();
useEffect(() => {
// Focus the input element when the component mounts
inputRef.current.focus();
}, []);
return <input ref={inputRef} />;
}
In the next article, we will focus on more optimization hooks like useMemo, and useCallback React provides to us.