React Hooks are functions that let you "hook into" React state and lifecycle features from functional components.
Introduced in: React 16.8 (February 2019)
What they do: Allow functional components to have state, lifecycle methods, context, refs, and more
Why they matter: Before Hooks, these features were only available in class components
Analogy: Hooks are like power adapters. Your functional component (like a laptop) can now plug into React's internal features (state and lifecycle) that were previously only available to class components.
2. The Problem Hooks Solve (Why Hooks Were Created)
Before Hooks, React had three major problems that made code difficult to write, understand, and reuse.
2.1 Problem 1: Wrapper Hell (HOCs and Render Props)
To reuse stateful logic between components, developers had to use Higher-Order Components (HOCs) or Render Props, which created deeply nested "wrapper hell."
JSX// BEFORE HOOKS: Wrapper Hell
export default withRouter(
withAuth(
withTheme(
withData(MyComponent)
)
)
);
// Result in JSX — "Pyramid of Doom"
<DataProvider>
<ThemeProvider>
<AuthProvider>
<RouterProvider>
<MyComponent />
</RouterProvider>
</AuthProvider>
</ThemeProvider>
</DataProvider>
The problem: Hard to debug, hard to type (TypeScript becomes complex), performance overhead from multiple wrapper layers.
JSX// AFTER HOOKS: Clean and flat
function MyComponent() {
const router = useRouter();
const user = useAuth();
const theme = useTheme();
const data = useData();
return <div>{data}</div>;
}
2.2 Problem 2: Giant Components with Complex Logic
Lifecycle methods forced related logic to be split across multiple methods, while unrelated logic was grouped together.
Before Hooks (React 16.7 and earlier), there were two ways to create components:
Option 1: Functional Components (Stateless)
JSX// Could only accept props and return JSX
// Could NOT have: State, Lifecycle methods, Refs, Context
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
The gap: You had to choose between simplicity (functional components with no features) or power (class components with complexity). Hooks bridge this gap — functional components can now do everything class components can do, with simpler syntax.
4. Types of React Hooks (Overview)
4.1 Basic Hooks (Most Commonly Used)
Hook
Purpose
Basic Syntax
useState
Add state to functional components
const [state, setState] = useState(initial)
useEffect
Side effects (API calls, DOM updates, subscriptions)
useEffect(() => { /* effect */ }, [deps])
useContext
Access React context without nesting
const value = useContext(MyContext)
4.2 Additional Hooks (Less Common but Powerful)
Hook
Purpose
useReducer
Complex state logic (like Redux but built-in)
useCallback
Memoize functions to prevent unnecessary re-renders
React Hooks have two rules that are absolutely mandatory. Breaking them will cause bugs that are hard to debug.
5.1 Rule 1: Only Call Hooks at the Top Level
Don't call Hooks inside loops, conditions, or nested functions. Always call them at the top level of your React function.
JSX// WRONG — Called inside condition
function BadComponent({ shouldUseHook }) {
if (shouldUseHook) {
const [count, setCount] = useState(0); // Conditional hook call!
}
}
// WRONG — Called inside loop or nested function
for (let i = 0; i < items.length; i++) {
const [state, setState] = useState(null);
}
// CORRECT — Called at top level
function GoodComponent() {
const [count, setCount] = useState(0);
if (count > 5) return <div>Count is high!</div>;
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Why this rule matters: React relies on the order of Hook calls to know which state belongs to which Hook. Conditional calls change the order and React gets confused.
5.2 Rule 2: Only Call Hooks from React Functions
Only call Hooks from React functional components or custom hooks (functions that start with use).
JSX// CLASS: 'this' confusion — bind, arrow wrapper, or broken handler
// HOOKS: Just regular functions
function Button() {
const handleClick = () => console.log('Clicked!');
return <button onClick={handleClick}>Click</button>;
}
6.6 Gradual Adoption (No Breaking Changes)
JSX// Mix class and functional components in the same app
class LegacyComponent extends React.Component {
render() {
return <NewHookComponent />;
}
}
function NewHookComponent() {
const [data, setData] = useState(null);
return <div>{data}</div>;
}
No need to rewrite existing class components — start using hooks in new components and migrate at your own pace.
7. Complete Working Examples
7.1 Example 1: Class Component vs Functional Component with Hooks
JSX// Class version
class Timer extends React.Component {
state = { seconds: 0 };
componentDidMount() {
this.interval = setInterval(() => {
this.setState(s => ({ seconds: s.seconds + 1 }));
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return <p>Elapsed: {this.state.seconds}s</p>;
}
}
// Hooks version — same behavior, less code
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(interval);
}, []);
return <p>Elapsed: {seconds}s</p>;
}
7.2 Example 2: Breaking Complex Logic into Multiple Hooks