Introduction
React has revolutionized the way we build user interfaces by introducing a component-based architecture. But the real game-changer came in
React 16.8 with the introduction of Hooks — a powerful feature that allows developers to use state and other React features in functional components.
Before Hooks, functional components were stateless and lacked lifecycle methods, which limited their capability. Hooks not only filled that gap but also simplified code and improved reusability. In this article, we’ll explore the
power of React Hooks, their use cases, and how they promote efficient
web development.
1. What Are React Hooks?
Hooks are built-in functions in React that let you “hook into” React’s state, lifecycle, and context features from functional components — without writing a class.
🔹 Commonly Used Hooks:
useState
– For managing stateuseEffect
– For handling side effectsuseContext
– For accessing contextuseRef
– For referencing DOM elementsuseMemo
– For memoizing expensive computationsuseCallback
– For optimizing performance with function references
2. useState – Manage State in Functional Components
The useState
hook allows you to add local state to a functional component.
✅ Example:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click Me</button>
</div>
);
}
🔸 Efficient and concise — no need for classes or this.setState
.
3. useEffect – Handling Side Effects
The useEffect
hook is used to handle side effects like API calls, event listeners, and subscriptions. It replaces lifecycle methods like
componentDidMount
, componentDidUpdate
, and componentWillUnmount
.
✅ Example:
import { useState, useEffect } from 'react';
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch('https://api.example.com/user/1')
.then(res => res.json())
.then(data => setUser(data));
}, []);
return user ? <div>Hello, {user.name}</div> : <p>Loading...</p>;
}
🔸 Clean and easy-to-read lifecycle handling in functional components.
4. useContext – Sharing State Across Components
useContext
simplifies state sharing between components using React Context API without prop drilling.
✅ Example:
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>I’m styled with {theme} theme!</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
🔸 Efficiently manages global state like themes, auth, or user settings.
5. useRef – Accessing the DOM and Mutable Values
useRef
is used to reference DOM elements or keep a mutable value that doesn’t cause re-renders.
✅ Example:
import { useRef } from 'react';
function InputFocus() {
const inputRef = useRef(null);
const focusInput = () => inputRef.current.focus();
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
🔸 Great for form handling, animations, and avoiding unnecessary renders.
6. useMemo – Optimizing Expensive Calculations
useMemo
caches the result of a calculation between renders if its dependencies haven’t changed.
✅ Example:
import { useMemo } from 'react';
function ExpensiveCalculation({ num }) {
const result = useMemo(() => {
let total = 0;
for (let i = 0; i < 100000000; i++) total += num;
return total;
}, [num]);
return <p>Result: {result}</p>;
}
🔸 Improves performance by preventing repeated heavy calculations.
7. useCallback – Prevent Unnecessary Re-Renders
useCallback
memoizes functions, ensuring they are not recreated on every render unless dependencies change.
✅ Example:
const handleClick = useCallback(() => {
console.log("Button clicked!");
}, []);
🔸 Useful when passing callbacks to optimized child components (like React.memo).