Since React 16.8, Hooks have transformed the way we write components. They allow you to use state, lifecycle methods, and other advanced features without writing class components. Here’s a complete guide to understanding the most essential Hooks, with practical examples.

✅ What is a Hook?
A Hook is a special function provided by React. It lets you “hook into” React features like state and lifecycle methods inside function components.
Two important rules:
- Hooks must be called at the top level of your component (not inside loops, conditions, or nested functions).
- Hooks can only be used in React function components or other custom Hooks.
useState – Managing Local State
useState
allows you to create local state within a component.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
useEffect – Side Effects
useEffect
is used to run side effects such as API calls, event listeners, or timeouts after rendering.
useEffect(() => {
console.log('Component mounted');
return () => {
console.log('Component unmounted');
};
}, []);
The second parameter []
controls when the effect runs.
useContext – Consuming Context
useContext
allows you to access values from a React context without passing props manually.
const ThemeContext = React.createContext('light');
function Button() {
const theme = useContext(ThemeContext);
return <button className={theme}>Click me</button>;
}
useRef – References and Persistent Values
useRef
is used to reference a DOM element or keep a mutable value across renders without causing a re-render.
const inputRef = useRef(null);
function FocusInput() {
return (
<>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</>
);
}
useMemo – Memoizing Expensive Calculations
useMemo
prevents expensive computations from running on every render.
const result = useMemo(() => computeHeavyTask(value), [value]);
useCallback – Memoizing Functions
useCallback
returns a memoized version of a callback function, useful when passing callbacks to child components.
const handleClick = useCallback(() => {
console.log('Clicked');
}, []);
useReducer – Complex State Management
useReducer
is helpful for managing complex state logic, or when using a Redux-like pattern.
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
useLayoutEffect – Synchronous Side Effects
useLayoutEffect
behaves like useEffect
, but fires synchronously after DOM mutations. Use it when reading layout or measuring DOM.
Creating Your Own Custom Hooks
You can combine multiple hooks into reusable logic by writing custom hooks.
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return width;
}
Hooks Summary
Hook | Purpose |
---|---|
useState | Local component state |
useEffect | Side effects and lifecycle |
useContext | Access React context |
useRef | DOM references / persistent values |
useMemo | Memoize expensive calculations |
useCallback | Memoize functions |
useReducer | Advanced state management |
useLayoutEffect | Synchronous layout effect |
Hooks have changed the way we build components in React. They bring more clarity, reusability, and power to your code. Experiment with each one in small projects to fully understand their behavior and strengths.
—
🔁 What’s your favorite React Hook? Share your thoughts in the comments below!