Sitemap
Egbalajoy

Egbalajoy

Tech Trainer | Web Developer. I share practical career roadmaps for new developers.

REACT HOOKS: The Simplified Guide

4 min readMar 18, 2026

--

Press enter or click to view image in full size

Hooks allow functions to have access to state and other React features without using classes. You can either use the built-in Hooks or combine them to build your own.

Rules of Hooks

Before you start, you must follow these rules or your app will break:

  • Only call Hooks at the top level: Don’t call Hooks inside loops, conditions, or nested functions.
  • Only call Hooks from React functions: Use them in functional components or custom Hooks, never in regular JavaScript functions or class components.
  • Hooks cannot be conditional: The order of Hook calls must stay the same on every render. (e.g., inside an if statement)
  • Importing: You must always import them first from the React library before usage.

useState

The Simplified Concept: State lets a component “remember” information like user input. For example, a form component uses state to store what you type.

Syntax:

const [state, setState] = useState(initialValue);

When to use:

Tracking strings, numbers, booleans, arrays, or objects that need to change on the screen.

Example (Updating an Array):

const [names, setNames] = useState([]);

setNames(["Alice", "Bob"]);

useEffect

The Simplified Concept: Your component’s main job is just to show things. But sometimes, it needs to do something extra “on the side” — like call an API or start a countdown. These are called Side Effects.

Syntax:

useEffect(() => 
{
/* logic */
}, [dependencyArray]);

Example

function UserProfile() {
const [user, setUser] = useState(null);

useEffect(() => {
// This runs once when the component "mounts" (appears)
fetch("https://api.example.com/user/1")
.then((response) => response.json())
.then((data) => setUser(data));

}, []); // The empty array [] means "only run once"

if (!user) return <p>Loading...</p>;

return <h1>Hello, {user.name}!</h1>;
}

When to use: Fetching data, starting timers, or listening for keyboard input.

The Dependency Rule:

  1. Empty Array []: Runs once when the component first appears.
  2. With Values [count]: Runs only when that specific value changes.
  3. No Array: Runs after every single render (not recommended for performance).

UseRef

The Simplified Concept: useRef is like a sticky note you keep on the side. You can write on it and update it anytime, but React doesn’t “notice” or redraw the screen when you do. It also lets you “reach into” the HTML.

Get Egbalajoy’s stories in your inbox

Join Medium for free to get updates from this writer.

Syntax:

const myRef = useRef(initialValue);

When to use:

  • Focusing an input field programmatically.
  • Storing a timer ID to clear it later.
  • Remembering a value without refreshing the UI

Example

const inputRef = useRef(null);

// This reaches into the DOM to focus the box
const focusInput = () => inputRef.current.focus();

return <input ref={inputRef} />;

useMemo

The Simplified Concept: This remembers the result of a heavy calculation (like sorting 200,000 items). It tells React: “Only redo this work if these specific values changed. Otherwise, just give me the saved result from last time.”

Syntax:

const result = useMemo(() => expensiveFunction(), [dependencies]);

When to use:

Sorting/filtering large lists or doing complex math that slows down your app.

Example(filtering large list):

import { useMemo, useState } from "react";

function ProductList({ products }) {
const [query, setQuery] = useState("");

// This "expensive" filter only runs when 'products' or 'query' changes
const filteredProducts = useMemo(() => {
console.log("Filtering items..."); // You'll see this only when necessary
return products.filter(p => p.name.includes(query));
}, [products, query]);

return (
<>
<input onChange={(e) => setQuery(e.target.value)} placeholder="Search..." />
<ul>
{filteredProducts.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
</>
);
}

useContext

Normally in React, if a parent has data and a deeply nested child needs it, you have to pass it down through every component in between even the ones that don’t use it. This is called prop drilling. useContext fixes this by letting you put data in one central place, and any component anywhere in your app can just grab it directly no need to drill it down through multiple layers

Syntax:

const value = useContext(MyContext);

When to use:

  • Logged-in user info.
  • Theme preference (Dark/Light mode).
  • App language settings.
  • Anything many components across your app need to know

Example

const ThemeContext = createContext('light');

function Display() {
const theme = useContext(ThemeContext);
return <div className={theme}>The current theme is {theme}</div>;
}

useCallback

While useMemo returns a value, useCallback returns a memoized function. .Memoizing a function means caching the result of a function so that it does not need to be recalculated.

The useCallback function only re-executes when one of its dependencies changes value.

Syntax

useCallback(callback, dependencies)

Where:

callback: The function that you want to memoize.

dependencies: An array of dependencies for the callback function. The memoized callback will only change if one of these dependencies has changed.

When to use: Passing functions to optimized child components (React.memo) to prevent them from re-rendering unnecessarily.

Example

const memoizedHandleClick = useCallback(() => {
console.log("Button clicked!");
}, []); // This function identity stays the same across renders

--

--

Egbalajoy
Egbalajoy