- React Tutorial
- React Home
- React Setup
- React Introduction
- React ES6
- React Render HTML
- React JSX
- React Components
- React Class
- React Props
- React Events
- React Conditional
- React Lists
- React Forms
- React Router
- React Memo
- React CSS Styling
- React Hooks
- What is a Hook?
- React useState
- React useEffect
- React useContext
- React useRef
- React useReducer
- React useCallback
- React useMemo
- React Custom Hooks
What is a Hook?
- A hook in React is a specialized function that allows you to "hook into" React state and lifecycle features from functional components.
- Introduced in React 16.8, Hooks solved the problem of "wrapper hell" and the complexity of managing
thisin class components, making code more direct and easier to reason about.
Developer Tip: Hooks are just JavaScript functions, but they follow two strict rules: only call them at the top level (not inside loops or conditions) and only call them from React function components or custom Hooks.
Purpose
- State Management: Hooks allow functional components to remember data between renders without needing a class.
- Side Effect Handling: They provide a unified way to handle operations like API calls, manual DOM updates, and subscriptions.
- Logic Reuse: Before Hooks, sharing logic between components required complex patterns like Higher-Order Components (HOCs). Now, you can extract logic into custom Hooks easily.
Best Practice: Use Hooks to separate your business logic from your UI logic. If you find a component getting too large, consider moving the stateful logic into a custom Hook (e.g.,
useAuth or useForm).
Key Hooks
- useState: The most common hook. It stores local state that triggers a re-render when updated.
- useEffect: The Swiss Army knife for side effects. It replaces lifecycle methods like
componentDidMount,componentDidUpdate, andcomponentWillUnmount. - useContext: A way to "teleport" data through the component tree without manually passing props at every level (prop drilling).
- useReducer: An alternative to
useStatefor complex state objects where the next state depends on the previous one, often used in patterns similar to Redux.
Benefits
- Readability: Functional components with Hooks are generally more concise and easier to read than class components.
- Testing: Logic extracted into Hooks can be tested independently of the UI.
- Tree Shaking: Hooks lead to smaller bundle sizes because they are easier for minifiers to optimize than class methods.
Example - useState
The useState hook returns a pair: the current state value and a function that lets you update it. This is useful for things like form inputs, toggle switches, or counters.
import React, { useState } from 'react';
const ExampleComponent = () => {
// We initialize 'count' at 0. 'setCount' is the function we'll use to change it.
const [count, setCount] = useState(0);
return (
<div>
<p>Current Count: {count}</p>
{/* When the button is clicked, we call setCount to trigger a re-render */}
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
};
Common Mistake: Trying to update state by modifying the variable directly (e.g.,
count = count + 1). React won't know the state changed. Always use the setter function (setCount) to ensure React re-renders the component.
Example - useEffect
The useEffect hook is where you perform tasks that talk to the "outside world," such as fetching data from an API or setting up a timer.
import React, { useState, useEffect } from 'react';
const DataFetchingComponent = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/items');
const result = await response.json();
setData(result);
} catch (error) {
console.error("Failed to fetch data", error);
} finally {
setLoading(false);
}
};
fetchData();
}, []); // The empty array [] means this effect runs once on mount.
if (loading) return <p>Loading...</p>;
return (
<div>
<h3>API Results:</h3>
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
Watch Out: Be very careful with the dependency array (the second argument in
useEffect). If you omit it entirely, the effect runs after every render, which can lead to performance issues or infinite loops when fetching data.