Introduction to React Hooks
React Hooks are special functions that allow developers to use React features such as state, effects, context, references, and reusable logic inside function components. Hooks make it easier to build interactive user interfaces without writing class components.
React introduced Hooks in React 16.8. Common examples include useState(), useEffect(), useContext(), and useRef(). Read the official React Hooks documentation.
Course link: JustAcademy React JS Training Course | Register for React JS Course Demo
1. Learning Objectives
- Understand what React Hooks are and why they are used.
- Learn how Hooks work in function components.
- Understand the purpose of commonly used built-in Hooks.
- Manage component state with
useState().
- Perform side effects with
useEffect().
- Share data using
useContext().
- Access DOM elements and store mutable values with
useRef().
- Understand the Rules of Hooks and create custom Hooks.
2. What Are React Hooks?
React Hooks are functions provided by React that let function components use React features. They help developers manage component state, synchronize with external systems, access context, and reuse stateful logic.
Example Without Hooks: Simple Function Component
function Welcome() {
return <h1>Welcome to React JS!</h1>;
}
export default Welcome;
This component displays a heading but does not need state or other Hooks.
Example With a Hook
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
export default Counter;
Explanation: The useState() Hook stores the counter value. When the button is clicked, setCount() updates the state, and React renders the updated count.
3. Why Were React Hooks Introduced?
Before Hooks, developers commonly used class components to manage state and lifecycle-related behavior. Hooks made many of these tasks possible in function components and provided a way to reuse stateful logic across components.
- Simpler components: Manage state without class syntax.
- Reusable logic: Extract common behavior into custom Hooks.
- State management: Store and update changing data.
- Effect handling: Synchronize components with browser APIs, subscriptions, and other external systems.
- Better organization: Group related logic together instead of spreading it across class lifecycle methods.
- Improved maintainability: Build reusable functions for common application behavior.
4. How Do React Hooks Work?
Hooks are called while React renders a function component or a custom Hook. React preserves the relevant state and associates Hook calls with the component across renders. When state changes, React can render the component again with the updated value.
Basic Workflow
- The component renders.
- A Hook reads state or prepares behavior for the component.
- The user interacts with the interface or an external event occurs.
- A state setter may update the stored state.
- React renders the component again when necessary.
- The user sees the updated interface.
Example
import { useState } from 'react';
function LikeButton() {
const [likes, setLikes] = useState(0);
return (
<button onClick={() => setLikes(previousLikes => previousLikes + 1)}>
Likes: {likes}
</button>
);
}
export default LikeButton;
The functional updater receives the previous state and returns the next state. This is useful when the new value depends on the previous value.
5. Commonly Used React Hooks
| Hook |
Purpose |
Common Example |
useState() |
Stores component state. |
Counter, form inputs, toggle buttons. |
useEffect() |
Synchronizes with external systems. |
Event listeners, subscriptions, browser APIs. |
useContext() |
Reads context from a provider. |
Theme, locale, shared user information. |
useRef() |
Stores a mutable reference without causing a re-render when it changes. |
DOM access, timer identifiers. |
useReducer() |
Manages state using a reducer function. |
Complex state transitions. |
useMemo() |
Caches a calculation result between renders when dependencies remain unchanged. |
Expensive derived calculations. |
useCallback() |
Caches a function definition between renders when dependencies remain unchanged. |
Passing callbacks to optimized child components. |
useId() |
Generates IDs useful for accessibility relationships. |
Connecting labels and input descriptions. |
| Custom Hooks |
Reuse stateful or effect-related logic. |
Window size, online status, reusable form behavior. |
These Hooks serve different purposes. Use the simplest Hook that fits the problem; performance Hooks such as useMemo() and useCallback() are optimizations, not requirements for every component.
6. useState() Hook
The useState() Hook lets a function component store and update state. It returns an array containing the current state value and a setter function.
Syntax
const [state, setState] = useState(initialValue);
state: the current value.
setState: the function used to request a state update.
initialValue: the initial state value.
Example: Counter
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
function increaseCount() {
setCount(previousCount => previousCount + 1);
}
function decreaseCount() {
setCount(previousCount => previousCount - 1);
}
return (
<div>
<h2>Counter: {count}</h2>
<button onClick={increaseCount}>Increase</button>
<button onClick={decreaseCount}>Decrease</button>
</div>
);
}
export default Counter;
Important Points
- State can hold strings, numbers, Booleans, arrays, objects, and other values.
- Updating state requests a re-render when React determines the state has changed.
- Do not directly mutate objects or arrays stored in state; create updated copies.
- Use a functional updater when the next state depends on the previous state.
7. useEffect() Hook
The useEffect() Hook synchronizes a component with an external system. Examples include browser event listeners, subscriptions, timers, and third-party widgets. It can also be used for data fetching when a suitable framework or data-fetching solution is not being used.
Syntax
useEffect(() => {
// Set up or synchronize with an external system.
return () => {
// Clean up when necessary.
};
}, [dependencies]);
Example: Updating the Browser Tab Title
import { useEffect, useState } from 'react';
function CounterTitle() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return (
<button onClick={() => setCount(previousCount => previousCount + 1)}>
Count: {count}
</button>
);
}
export default CounterTitle;
When count changes, the Effect updates the browser tab title.
Understanding Dependencies
| Dependency Pattern |
Meaning |
useEffect(() => {...}) |
Runs after every commit in which the component renders. |
useEffect(() => {...}, []) |
Runs its setup after the initial mount; development Strict Mode may perform an extra setup-and-cleanup cycle. |
useEffect(() => {...}, [value]) |
Runs after the initial mount and again when the dependency changes. |
Important: Every reactive value used by an Effect must be handled correctly in its dependency list. Return a cleanup function when setup creates a subscription, listener, timer, or other resource that needs to be released. Effects are not needed for every calculation or event handler.
8. useContext() Hook
The useContext() Hook reads a value from a React context. It helps share information with deeply nested components without passing the same props through every intermediate component.
Example: Theme Context
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemeMessage() {
const theme = useContext(ThemeContext);
return <p>Current theme: {theme}</p>;
}
function App() {
return (
<ThemeContext value="dark">
<ThemeMessage />
</ThemeContext>
);
}
export default App;
In modern React, a context object can be used as a provider as shown above. In React versions before React 19, use . The component reads the nearest provider's value.
Common Uses
- Theme preferences.
- Language and localization settings.
- Shared authentication or user information.
- Application-wide configuration.
9. useRef() Hook
The useRef() Hook stores a mutable value that remains available between renders. Updating its current property does not itself trigger a re-render. Refs can also point to DOM elements.
Example: Focusing an Input
import { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(null);
function handleFocus() {
inputRef.current?.focus();
}
return (
<div>
<input ref={inputRef} placeholder="Enter your name" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
export default FocusInput;
When the button is clicked, the input receives focus through its DOM reference.
Common Uses
- Focusing or selecting DOM elements.
- Storing timer IDs or other mutable values.
- Keeping a value between renders when changing it should not update the UI.
10. useReducer() Hook
The useReducer() Hook is useful when state transitions are more complex or when multiple actions update the same state. It uses a reducer function that receives the current state and an action, then returns the next state.
Syntax
const [state, dispatch] = useReducer(reducer, initialState);
Example: Counter Using useReducer
import { useReducer } from 'react';
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
case 'reset':
return { count: 0 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<h2>Count: {state.count}</h2>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</div>
);
}
export default Counter;
dispatch() sends an action to the reducer, which determines the next state.
11. useMemo() and useCallback()
11.1 useMemo()
useMemo() caches the result of a calculation between renders while its dependencies remain unchanged. It can help avoid repeated expensive calculations.
import { useMemo, useState } from 'react';
function PriceCalculator() {
const [price, setPrice] = useState(100);
const [quantity, setQuantity] = useState(1);
const total = useMemo(() => {
return price * quantity;
}, [price, quantity]);
return (
<div>
<p>Total: {total}</p>
<button onClick={() => setQuantity(q => q + 1)}>
Add One Item
</button>
</div>
);
}
11.2 useCallback()
useCallback() caches a function definition between renders while its dependencies remain unchanged. It is especially useful when passing callbacks to memoized child components or when a stable function reference is needed.
import { useCallback, useState } from 'react';
function SearchExample() {
const [query, setQuery] = useState('');
const clearQuery = useCallback(() => {
setQuery('');
}, []);
return (
<div>
<input
value={query}
onChange={event => setQuery(event.target.value)}
/>
<button onClick={clearQuery}>Clear</button>
</div>
);
}
Neither Hook should be added automatically to every component. Use them when caching provides a meaningful benefit or is needed for a particular optimization.
12. What Are Custom Hooks?
A custom Hook is a JavaScript function whose name starts with use and that can call other Hooks. Custom Hooks let developers reuse stateful logic across multiple components without duplicating the same implementation.
Example: Custom Counter Hook
import { useState } from 'react';
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
function increment() {
setCount(previousCount => previousCount + 1);
}
function decrement() {
setCount(previousCount => previousCount - 1);
}
function reset() {
setCount(initialValue);
}
return { count, increment, decrement, reset };
}
export default useCounter;
Using the Custom Hook
import useCounter from './useCounter';
function Counter() {
const { count, increment, decrement, reset } = useCounter(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>Increase</button>
<button onClick={decrement}>Decrease</button>
<button onClick={reset}>Reset</button>
</div>
);
}
export default Counter;
Each component calling this custom Hook gets its own independent state unless the Hook explicitly connects to shared state or an external store.
13. Rules of React Hooks
React Hooks must follow specific rules so React can correctly preserve state and other Hook behavior between renders.
- Call Hooks at the top level: Do not call Hooks inside loops, conditions, nested functions, or
try/catch/finally blocks.
- Call Hooks from React functions: Call Hooks from function components or custom Hooks, not ordinary JavaScript functions.
- Keep Hook calls in a consistent order: Do not skip Hook calls based on conditions.
- Use meaningful custom Hook names: Custom Hook names should start with
use.
- Follow dependency rules: For Effects and memoization Hooks, specify reactive dependencies correctly.
- Do not mutate state directly: Use the appropriate state setter or reducer dispatch.
Incorrect Example
function Example({ enabled }) {
if (enabled) {
const [count, setCount] = useState(0);
}
return <div>Example</div>;
}
Correct Example
function Example({ enabled }) {
const [count, setCount] = useState(0);
if (!enabled) {
return <div>Disabled</div>;
}
return (
<button onClick={() => setCount(c => c + 1)}>
Count: {count}
</button>
);
}
Call the Hook before the conditional return so it is called in the same order on every render.
14. React Hooks vs. Class Components
| Feature |
Function Components with Hooks |
Class Components |
| State |
Managed with Hooks such as useState() and useReducer(). |
Commonly managed with this.state. |
| Lifecycle behavior |
Effects synchronize with external systems. |
Lifecycle methods such as componentDidMount() and componentWillUnmount(). |
| Reusable logic |
Custom Hooks can share stateful logic. |
Often uses other patterns, such as higher-order components or render props. |
| Syntax |
JavaScript functions. |
JavaScript classes. |
| New development |
Commonly preferred for modern React components. |
Still supported; existing class components do not need to be rewritten immediately. |
15. Common Mistakes When Using Hooks
| Mistake |
Why It Is a Problem |
Solution |
| Calling a Hook inside a condition |
Hook call order may change between renders. |
Move the Hook to the top level. |
| Calling Hooks in regular functions |
React cannot manage them as component or custom Hook calls. |
Call Hooks only in function components or custom Hooks. |
| Mutating state directly |
React may not detect the intended change. |
Create new objects or arrays and use the setter. |
| Incorrect Effect dependencies |
The Effect may use outdated values or run too often. |
Include all required reactive dependencies and review the Effect logic. |
| Using Effects for simple calculations |
Can create unnecessary state and extra rendering. |
Calculate values during rendering when appropriate. |
| Overusing useMemo or useCallback |
Adds complexity without always improving performance. |
Optimize when there is a clear reason. |
| Forgetting cleanup |
Listeners, timers, or subscriptions may remain active unnecessarily. |
Return a cleanup function when required. |
16. Mini Project: Interactive Profile Card
Objective: Build a profile card that uses React Hooks to update a person's name, toggle profile details, and change the theme.
Complete Code
import { useState } from 'react';
function ProfileCard() {
const [name, setName] = useState('Alex');
const [showDetails, setShowDetails] = useState(false);
const [darkMode, setDarkMode] = useState(false);
const cardStyle = {
padding: '20px',
borderRadius: '8px',
backgroundColor: darkMode ? '#222' : '#f2f2f2',
color: darkMode ? '#fff' : '#222'
};
return (
<div style={cardStyle}>
<h2>Profile Card</h2>
<label htmlFor="profile-name">Name:</label>
<input
id="profile-name"
value={name}
onChange={event => setName(event.target.value)}
/>
<h3>Hello, {name || 'Guest'}!</h3>
<button onClick={() => setShowDetails(value => !value)}>
{showDetails ? 'Hide Details' : 'Show Details'}
</button>
{showDetails && (
<p>This profile card demonstrates React state and conditional rendering.</p>
)}
<button onClick={() => setDarkMode(value => !value)}>
{darkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
</button>
</div>
);
}
export default ProfileCard;
Hooks Used
useState() manages the name, details visibility, and theme.
- State updates trigger rendering of the changed interface.
- Conditional rendering displays or hides the profile details.
- The theme state determines the card's inline styles.
17. Interview Questions and Answers
Q1. What are React Hooks?
React Hooks are functions that allow function components to use React features such as state, effects, context, and refs.
Q2. Why are Hooks used in React?
Hooks simplify state management in function components and allow developers to reuse stateful logic through custom Hooks.
Q3. What is useState()?
useState() declares a state variable and returns its current value and a setter function.
Q4. What is useEffect()?
useEffect() synchronizes a component with external systems, such as subscriptions, browser APIs, or timers.
Q5. What is useContext()?
useContext() reads a context value from the closest matching provider above the component.
Q6. What is useRef()?
useRef() stores a mutable value between renders or provides a reference to a DOM element without triggering a re-render when its current value changes.
Q7. What is a custom Hook?
A custom Hook is a function whose name starts with use and that combines Hooks to reuse logic across components.
Q8. Can Hooks be used inside class components?
No. Hooks are used in function components and custom Hooks, not directly inside class components.
Q9. Why must Hooks be called at the top level?
React relies on a consistent order of Hook calls to associate state and other Hook data with the correct component.
Q10. What is the difference between useMemo() and useCallback()?
useMemo() caches a calculation result, while useCallback() caches a function definition.
Q11. What is useReducer()?
useReducer() manages state through a reducer function and dispatched actions, making complex state transitions easier to organize.
Q12. Do all React components need Hooks?
No. Components that only display information may not need Hooks. Use Hooks when a component needs state, effects, context, refs, or other Hook-supported functionality.
18. Practice Exercises
- Create a counter with Increase, Decrease, and Reset buttons using
useState().
- Create a form that stores a name and email in state.
- Use
useEffect() to update the browser tab title when a counter changes.
- Build a theme switcher using
useContext().
- Use
useRef() to focus an input field when a button is clicked.
- Create a to-do list using
useState().
- Manage multiple counter actions using
useReducer().
- Use
useMemo() to cache an expensive calculation when needed.
- Create a custom Hook that manages a counter or reusable form logic.
- Build a profile card with editable information and conditional details.
19. Revision Checklist
- Understand the definition and purpose of React Hooks.
- Know why Hooks are useful in function components.
- Understand
useState() and state updates.
- Understand
useEffect(), dependencies, and cleanup.
- Know how
useContext() shares values.
- Know how
useRef() stores mutable values and references DOM elements.
- Understand when
useReducer() is useful.
- Understand the difference between
useMemo() and useCallback().
- Know how to create and use custom Hooks.
- Follow the Rules of Hooks.
- Practice building small React projects using Hooks.
20. Additional Learning Resources
Conclusion
React Hooks make it possible to use state, effects, context, refs, and reusable logic in function components. Start with useState() and useEffect(), then learn useContext(), useRef(), useReducer(), performance Hooks, and custom Hooks. Practicing these concepts through small projects will help you build maintainable and interactive React applications.
Explore the JustAcademy React JS Training Course or register for a React JS course demo.