React is an open source JavaScript library for building awesome and complex user interfaces and is one of the most popular in the JavaScript ecosystem.
TLDR 📜
React hooks are functions that allow you to use React state and other features within functional components, enabling tasks like handling side effects and accessing context without writing complex React classes. Using React hooks also enhances code readability and maintainability for developers.
In this article, I will share a list of the 38 React.js hooks and their use cases, which can be considered one of the best resources for React and JavaScript developers.
1. useState
Manages local component state.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<p>Count: {count}</p>
</div>
);
}
2. useEffect
Performs side effects in function components.
import { useEffect, useState } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
return <div>Data: {data ? JSON.stringify(data) : 'Loading...'}</div>;
}
3. useContext
Consumes context in a component.
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme.background }}>Click me</button>;
}
4.useReducer
Manages complex state logic
import { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<span>{state.count}</span>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
</div>
);
}
5. useCallback
Returns a memoized callback function.
import { useCallback, useState } from 'react';
function CallbackComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(count + 1);
}, [count]);
return <button onClick={increment}>Count: {count}</button>;
}
6. useMemo
Memoizes expensive calculations i.e stores results of resource-intensive calculations for future use.
import { useMemo, useState } from 'react';
function Fibonacci() {
const [num, setNum] = useState(1);
const fib = useMemo(() => {
const computeFib = (n) => (n <= 1 ? n : computeFib(n - 1) + computeFib(n - 2));
return computeFib(num);
}, [num]);
return (
<div>
<button onClick={() => setNum(num + 1)}>Next Fibonacci</button>
<p>Fibonacci of {num} is {fib}</p>
</div>
);
}
7.useRef
Accesses DOM elements or stores mutable values.
import { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
}
8.useImperativeHandle
Customizes the instance value exposed by a ref.
import { forwardRef, useImperativeHandle, useRef } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
}));
return <input ref={inputRef} />;
});
function App() {
const fancyInputRef = useRef();
return (
<div>
<FancyInput ref={fancyInputRef} />
<button onClick={() => fancyInputRef.current.focus()}>Focus input</button>
</div>
);
}
9. useLayoutEffect
Synchronizes with the DOM layout.
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
function MeasureWidth() {
const ref = useRef();
const [width, setWidth] = useState(0);
useLayoutEffect(() => {
setWidth(ref.current.offsetWidth);
}, []);
return (
<div>
<div ref={ref} style={{ width: '50%' }}>
Resize the window to see the effect.
</div>
<p>Width: {width}px</p>
</div>
);
}
10.useDebugValue
Displays custom label in React DevTools.
import { useDebugValue, useState } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useDebugValue(isOnline ? 'Online' : 'Offline');
// Simulate an asynchronous operation
setTimeout(() => setIsOnline(Math.random() > 0.5), 1000);
return isOnline;
}
function FriendStatus({ friendID }) {
const isOnline = useFriendStatus(friendID);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
11.useFetch
Fetches data from an API.
import { useEffect, useState } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
});
}, [url]);
return { data, loading };
}
function App() {
const { data, loading } = useFetch('https://jsonplaceholder.typicode.com/posts');
if (loading) {
return <p>Loading...</p>;
}
return (
<ul>
{data.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
12.useLocalStorage
Manages state with local storage.
import { useState } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
function App() {
const [name, setName] = useLocalStorage('name', 'Bob');
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
<p>Hello, {name}!</p>
</div>
);
}
13. useDebounce
Debounces a value over time.
import { useEffect, useState } from 'react';
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
function App() {
const [text, setText] = useState('');
const debouncedText = useDebounce(text, 500);
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<p>Debounced Value: {debouncedText}</p>
</div>
);
}
14.usePrevious
Stores the previous value of a variable.
import { useEffect, useRef } from 'react';
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
function App() {
const [count, setCount] = useState(0);
const previousCount = usePrevious(count);
return (
<div>
<button onClick={() => setCount(count + 1)}>Count: {count}</button>
<p>Previous Count: {previousCount}</p>
</div>
);
}
15. useWindowSize
Tracks window size.
import { useEffect, useState } from 'react';
function useWindowSize() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
function App() {
const { width, height } = useWindowSize();
return (
<div>
<p>Width: {width}px</p>
<p>Height: {height}px</p>
</div>
);
}
16.useHover
Detects if an element is hovered.
import { useCallback, useState } from 'react';
function useHover() {
const [hovered, setHovered] = useState(false);
const onMouseOver = useCallback(() => setHovered(true), []);
const onMouseOut = useCallback(() => setHovered(false), []);
return { hovered, onMouseOver, onMouseOut };
}
function HoverComponent() {
const { hovered, onMouseOver, onMouseOut } = useHover();
return (
<div onMouseOver={onMouseOver} onMouseOut={onMouseOut}>
{hovered ? 'Hovering' : 'Not Hovering'}
</div>
);
}
17. useOnlineStatus
Tracks online status.
import { useEffect, useState } from 'react';
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return isOnline;
}
function App() {
const isOnline = useOnlineStatus();
return <div>{isOnline ? 'Online' : 'Offline'}</div>;
}
18. useEventListener
Attaches an event listener.
import { useEffect, useRef } from 'react';
function useEventListener(eventName, handler, element = window) {
const savedHandler = useRef();
useEffect(() => {
savedHandler.current = handler;
}, [handler]);
useEffect(() => {
const eventListener = (event) => savedHandler.current(event);
element.addEventListener(eventName, eventListener);
return () => {
element.removeEventListener(eventName, eventListener);
};
}, [eventName, element]);
}
function App() {
useEventListener('click', () => alert('Window clicked!'));
return <div>Click anywhere!</div>;
}
19.useInterval
Sets up an interval with a dynamic delay.
import { useEffect, useRef } from 'react';
function useInterval(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
function Timer() {
const [count, setCount] = useState(0);
useInterval(() => setCount(count + 1), 1000);
return <div>Count: {count}</div>;
}
20. useTimeout
Sets up a timeout.
import { useEffect, useRef } from 'react';
function useTimeout(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
const id = setTimeout(tick, delay);
return () => clearTimeout(id);
}
}, [delay]);
}
function App() {
const [visible, setVisible] = useState(true);
useTimeout(() => setVisible(false), 5000);
return <div>{visible ? 'Visible for 5 seconds' : 'Hidden'}</div>;
}
21. useOnClickOutside
Detects clicks outside a component.
import { useEffect, useRef } from 'react';
function useOnClickOutside(ref, handler) {
useEffect(() => {
const listener = (event) => {
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [ref, handler]);
}
function App() {
const ref = useRef();
const [isVisible, setIsVisible] = useState(true);
useOnClickOutside(ref, () => setIsVisible(false));
return (
<div>
<div ref={ref} style={{ display: isVisible ? 'block' : 'none' }}>
Click outside this box to hide it.
</div>
</div>
);
}
22. useClipboard
Handles clipboard operations.
import { useState } from 'react';
function useClipboard() {
const [copied, setCopied] = useState(false);
const copy = (text) => {
navigator.clipboard.writeText(text).then(() => setCopied(true));
};
return { copied, copy };
}
function App() {
const { copied, copy } = useClipboard();
return (
<div>
<button onClick={() => copy('Hello, world!')}>
{copied ? 'Copied!' : 'Copy'}
</button>
</div>
);
}
23. useDarkMode
Manages dark mode preference.
import { useEffect, useState } from 'react';
function useDarkMode() {
const [isDarkMode, setIsDarkMode] = useState(false);
useEffect(() => {
const darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
setIsDarkMode(darkMode);
}, []);
return isDarkMode;
}
function App() {
const isDarkMode = useDarkMode();
return <div>{isDarkMode ? 'Dark Mode' : 'Light Mode'}</div>;
}
24.useToggle
Toggles between boolean values.
import { useState } from 'react';
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = () => setValue(!value);
return [value, toggle];
}
function App() {
const [isToggled, toggle] = useToggle();
return (
<div>
<button onClick={toggle}>{isToggled ? 'On' : 'Off'}</button>
</div>
);
}
25. useTheme
Toggles between light and dark themes.
import { useEffect, useState } from 'react';
function useTheme() {
const [theme, setTheme] = useState('light');
useEffect(() => {
document.body.className = theme;
}, [theme]);
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return { theme, toggleTheme };
}
function App() {
const { theme, toggleTheme } = useTheme();
return (
<div>
<p>Current Theme: {theme}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
26. useMedia
Queries media properties.
import { useEffect, useState } from 'react';
function useMedia(query) {
const [matches, setMatches] = useState(window.matchMedia(query).matches);
useEffect(() => {
const mediaQueryList = window.matchMedia(query);
const listener = (event) => setMatches(event.matches);
mediaQueryList.addListener(listener);
return () => mediaQueryList.removeListener(listener);
}, [query]);
return matches;
}
function App() {
const isLargeScreen = useMedia('(min-width: 800px)');
return <div>{isLargeScreen ? 'Large Screen' : 'Small Screen'}</div>;
}
27. useLockBodyScroll
Locks the body scroll.
import { useEffect } from 'react';
function useLockBodyScroll() {
useEffect(() => {
const originalOverflow = window.getComputedStyle(document.body).overflow;
document.body.style.overflow = 'hidden';
return () => (document.body.style.overflow = originalOverflow);
}, []);
}
function App() {
useLockBodyScroll();
return <div>Body scroll is locked</div>;
}
28.useKeyPress
Detects key press.
import { useEffect, useState } from 'react';
function useKeyPress(targetKey) {
const [keyPressed, setKeyPressed] = useState(false);
useEffect(() => {
const downHandler = ({ key }) => {
if (key === targetKey) setKeyPressed(true);
};
const upHandler = ({ key }) => {
if (key === targetKey) setKeyPressed(false);
};
window.addEventListener('keydown', downHandler);
window.addEventListener('keyup', upHandler);
return () => {
window.removeEventListener('keydown', downHandler);
window.removeEventListener('keyup', upHandler);
};
}, [targetKey]);
return keyPressed;
}
function App() {
const aPressed = useKeyPress('a');
return <div>{aPressed ? 'A is pressed' : 'Press A'}</div>;
}
29. useDocumentTitle
Updates document title.
import { useEffect } from 'react';
function useDocumentTitle(title) {
useEffect(() => {
document.title = title;
}, [title]);
}
function App() {
useDocumentTitle('Custom Title');
return <div>Check the document title</div>;
}
30. useHover
Handles hover state.
import { useCallback, useState } from 'react';
function useHover() {
const [hovered, setHovered] = useState(false);
const onMouseOver = useCallback(() => setHovered(true), []);
const onMouseOut = useCallback(() => setHovered(false), []);
return { hovered, onMouseOver, onMouseOut };
}
function HoverComponent() {
const { hovered, onMouseOver, onMouseOut } = useHover();
return (
<div onMouseOver={onMouseOver} onMouseOut={onMouseOut}>
{hovered ? 'Hovering' : 'Not Hovering'}
</div>
);
}
31.useGeolocation
Retrieves geolocation.
import { useEffect, useState } from 'react';
function useGeolocation() {
const [location, setLocation] = useState({});
useEffect(() => {
navigator.geolocation.getCurrentPosition(
(position) => setLocation(position.coords),
(error) => console.error(error)
);
}, []);
return location;
}
function App() {
const { latitude, longitude } = useGeolocation();
return (
<div>
<p>Latitude: {latitude}</p>
<p>Longitude: {longitude}</p>
</div>
);
}
32. useScrollPosition
Tracks scroll position.
import { useEffect, useState } from 'react';
function useScrollPosition() {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleScroll = () => {
setPosition({ x: window.scrollX, y: window.scrollY });
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return position;
}
function App() {
const { x, y } = useScrollPosition();
return (
<div>
<p>Scroll Position: {`x: ${x}, y: ${y}`}</p>
</div>
);
}
33. useUnmount
Runs a function when a component unmounts.
import { useEffect } from 'react';
function useUnmount(callback) {
useEffect(() => {
return () => callback();
}, [callback]);
}
function App() {
useUnmount(() => {
console.log('Component will unmount');
});
return <div>Unmount me to see the console message.</div>;
}
34. useClickOutside
Detects clicks outside an element.
import { useEffect, useRef } from 'react';
function useClickOutside(handler) {
const ref = useRef();
useEffect(() => {
const listener = (event) => {
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [handler]);
return ref;
}
function App() {
const handleClickOutside = () => {
console.log('Clicked outside!');
};
const ref = useClickOutside(handleClickOutside);
return (
<div ref={ref} style={{ padding: '50px', border: '1px solid black' }}>
Click outside me!
</div>
);
}
35. useDebouncedCallback
Debounces a callback function.
import { useCallback, useState } from 'react';
function useDebouncedCallback(callback, delay) {
const [timeoutId, setTimeoutId] = useState(null);
const debouncedCallback = useCallback((...args) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
const id = setTimeout(() => {
callback(...args);
}, delay);
setTimeoutId(id);
}, [callback, delay]);
return debouncedCallback;
}
function App() {
const [value, setValue] = useState('');
const handleChange = useDebouncedCallback((e) => {
setValue(e.target.value);
}, 500);
return (
<input type="text" onChange={handleChange} />
);
}
36. useThrottle
Throttles a value over time.
import { useEffect, useState } from 'react';
function useThrottle(value, limit) {
const [throttledValue, setThrottledValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setThrottledValue(value);
}, limit);
return () => {
clearTimeout(handler);
};
}, [value, limit]);
return throttledValue;
}
function App() {
const [text, setText] = useState('');
const throttledText = useThrottle(text, 1000);
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<p>Throttled Value: {throttledText}</p>
</div>
);
}
37. useUpdateEffect
Runs an effect only on updates, not on mount.
import { useEffect, useRef } from 'react';
function useUpdateEffect(effect, dependencies) {
const isInitialMount = useRef(true);
useEffect(() => {
if (isInitialMount.current) {
isInitialMount.current = false;
} else {
effect();
}
}, dependencies);
}
function App() {
const [count, setCount] = useState(0);
useUpdateEffect(() => {
console.log('Component updated');
}, [count]);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<p>Count: {count}</p>
</div>
);
}
38.useLocalStorage
Manages state in local storage
import { useEffect, useState } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
const setValue = (value) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue];
}
function App() {
const [name, setName] = useLocalStorage('name', 'Guest');
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
</div>
);
}
React.js is easy to learn and master, with numerous free courses and resources, plus a massive and active developer community
Make sure to use these React hooks in your next project and follow me for more content like this
GIF CREDIT
If you like the gif make sure to follow Jeremy the manager on instagram