Hooks --- useEffect, useContext & Custom Hooks
⏱ 18 min read read
useEffect --- Side Effects in Client Components:
useEffect(() => {
// runs after render
return () => { /* cleanup */ };
}, [dependencies]);
useEffect(() => { ... }, []); // run once on mount
useEffect(() => { ... }); // run after every render
useEffect(() => { ... }, [id]); // run when 'id' changes
In Next.js, prefer Server Components for data fetching over
useEffect.
useEffect runs ONLY in the browser --- avoid for initial data loads.
Common legitimate uses: subscriptions, timers, window event
listeners,
syncing with external non-React systems, localStorage.
Always return a cleanup function for subscriptions and timers.
useContext --- Share State Without Prop Drilling:
// 1. Create context
const ThemeContext = createContext<'light' |
'dark'>('light');
// 2. Provide it high up in the tree
function App() {
const [theme, setTheme] = useState<'light' |
'dark'>('light');
return (
<ThemeContext.Provider value={theme}>
<Page />
</ThemeContext.Provider>
);
}
// 3. Consume anywhere in the tree
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click</button>;
}
Custom Hooks --- Reusable Logic:
A custom hook is just a function that starts with 'use' and calls
other hooks. Extract repeated patterns into custom hooks.
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
if (typeof window === 'undefined') return initialValue;
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
const set = (v: T) => {
setValue(v);
localStorage.setItem(key, JSON.stringify(v));
};
return [value, set] as const;
}
// Usage
const [name, setName] = useLocalStorage('username', '');
useEffect(() => {
// runs after render
return () => { /* cleanup */ };
}, [dependencies]);
useEffect(() => { ... }, []); // run once on mount
useEffect(() => { ... }); // run after every render
useEffect(() => { ... }, [id]); // run when 'id' changes
In Next.js, prefer Server Components for data fetching over
useEffect.
useEffect runs ONLY in the browser --- avoid for initial data loads.
Common legitimate uses: subscriptions, timers, window event
listeners,
syncing with external non-React systems, localStorage.
Always return a cleanup function for subscriptions and timers.
useContext --- Share State Without Prop Drilling:
// 1. Create context
const ThemeContext = createContext<'light' |
'dark'>('light');
// 2. Provide it high up in the tree
function App() {
const [theme, setTheme] = useState<'light' |
'dark'>('light');
return (
<ThemeContext.Provider value={theme}>
<Page />
</ThemeContext.Provider>
);
}
// 3. Consume anywhere in the tree
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click</button>;
}
Custom Hooks --- Reusable Logic:
A custom hook is just a function that starts with 'use' and calls
other hooks. Extract repeated patterns into custom hooks.
function useLocalStorage<T>(key: string, initialValue: T) {
const [value, setValue] = useState<T>(() => {
if (typeof window === 'undefined') return initialValue;
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
const set = (v: T) => {
setValue(v);
localStorage.setItem(key, JSON.stringify(v));
};
return [value, set] as const;
}
// Usage
const [name, setName] = useLocalStorage('username', '');
Log in to track your progress and earn badges as you complete lessons.
Log In to Track Progress