React Hooks Guide
Introduction to Hooks
Hooks are functions that let you "hook into" React state and lifecycle features from function components. Introduced in React 16.8, they allow you to use state and other React features without writing classes.
Why Use Hooks?
- Simplify complex components
- Reuse stateful logic without classes
- Organize related logic into single hook
- Reduce boilerplate code
- Easier to test and maintain
Basic Hooks
useState
Manages state in functional components. Returns a stateful value and a function to update it.
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>
);
}useEffect
Performs side effects in function components (data fetching, subscriptions, DOM manipulation).
import { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(res => res.json())
.then(data => setData(data));
return () => {
// Cleanup function (runs on unmount)
};
}, []); // Empty array means run once on mount
return <div>{data ? data.message : 'Loading...'}</div>;
}useContext
Accesses context values without nesting consumers.
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>I'm styled by theme!</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}Additional Hooks
useReducer
Alternative to useState for complex state logic
const [state, dispatch] = useReducer(reducer, initialState);
useCallback
Memoizes functions to prevent unnecessary re-renders
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);useMemo
Memoizes expensive calculations
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useRef
Creates mutable ref object that persists
const inputRef = useRef(null);
<input ref={inputRef} />useImperativeHandle
Customizes instance value exposed to parent components
useImperativeHandle(ref, () => ({ focus: () => { /* ... */ } }));useLayoutEffect
Same as useEffect but fires synchronously after DOM mutations
useLayoutEffect(() => { /* measure DOM */ });useDebugValue
Displays custom labels in React DevTools
useDebugValue(isOnline ? 'Online' : 'Offline');
Custom Hooks
You can create your own hooks to extract component logic into reusable functions.
Example: useFetch
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Usage:
function MyComponent() {
const { data, loading, error } = useFetch('https://api.example.com/data');
// ...
}Hooks Best Practices
Call Hooks at the Top Level
Don't call hooks inside loops, conditions, or nested functions
Only Call Hooks from React Functions
Call them from React components or custom hooks
Use Multiple Effects
Separate concerns by using multiple useEffect hooks
Optimize Dependencies
Include all dependencies used in your effect
Memoize Expensive Operations
Use useMemo/useCallback for performance optimization
Clean Up Effects
Always return cleanup functions when needed