Getting Started with React Hooks
React Hooks were introduced in React 16.8 and fundamentally changed how we write components. If you're still using class components, you're missing out on cleaner, more readable code.
Why Hooks Matter
Before Hooks, functional components were limited β they couldn't hold state, couldn't access lifecycle methods, and couldn't reuse logic easily. Hooks changed all of that.
Think of Hooks as giving superpowers to functions. A simple function that used to just receive props and return JSX can now manage state, perform side effects, and share logic across components.
useState Hook
This is your bread and butter. It lets you add state to any functional component:
import React, { 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>
);
}The beauty of this API is its simplicity. One line gives you a state variable and a setter function. No more this.state, no more this.setState, no more binding.
useEffect Hook
Side effects are everything from fetching data to updating the DOM. useEffect lets you handle them declaratively:
import { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUser() {
const res = await fetch("/api/users/" + userId);
const data = await res.json();
setUser(data);
setLoading(false);
}
fetchUser();
}, [userId]);
if (loading) return <p>Loading...</p>;
return <div>{user.name}</div>;
}Common Mistakes
- Infinite loops: Forgetting the dependency array causes useEffect to run on every render.
- Stale closures: When your effect captures an old value of a variable. Include dependencies or use functional updates.
Pro Tips
- Use
useCallbackto memoize functions passed to child components - Use
useMemofor expensive computations - Custom Hooks let you extract and share stateful logic
- Hooks Rules: only call them at the top level, never in loops or conditions
