React Hooks – Complete Beginner-Friendly Guide (with Examples)
React Hooks allow you to use state and other React features in functional components without writing class components. Introduced in React 16.8, hooks make code cleaner, reusable, and easier to understand.
Why React Hooks?
Before hooks:
With hooks:
1. useState – Managing State
Why use useState?
To store and update data that changes over time (counter, input value, toggle, etc.)
When to use?
Example: Counter App
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
export default Counter;
📌 Explanation:
2. useEffect – Side Effects
Why use useEffect?
To perform side effects like:
When to use?
Example: Run Code on Component Load
import React, { useEffect } from "react";
function Example() {
useEffect(() => {
console.log("Component Mounted");
}, []);
return <h2>Hello React</h2>;
}
export default Example;
📌 Explanation:
3. useRef – Accessing DOM or Persisting Values
Why use useRef?
When to use?
Example: Focus Input on Button Click
import React, { useRef } from "react";
function FocusInput() {
const inputRef = useRef(null);
return (
<div>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>
Focus Input
</button>
</div>
);
}
export default FocusInput;
📌 Explanation:
4. useCallback – Optimize Functions
Why use useCallback?
To prevent unnecessary function re-creation, improving performance.
When to use?
Example: Optimized Function
import React, { useState, useCallback } from "react";
function Button({ handleClick }) {
return <button onClick={handleClick}>Click Me</button>;
}
function App() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prev) => prev + 1);
}, []);
return (
<div>
<h2>{count}</h2>
<Button handleClick={increment} />
</div>
);
}
export default App;
📌 Explanation:
5. useMemo – Memoize Values
Why use useMemo?
To avoid expensive calculations on every render.
When to use?
Example
import React, { useState, useMemo } from "react";
function ExpensiveCalc({ num }) {
const result = useMemo(() => {
console.log("Calculating...");
return num * 2;
}, [num]);
return <h2>Result: {result}</h2>;
}
export default ExpensiveCalc;
📌 Key Point: useMemo caches the value, not the function.
6. useContext – Avoid Prop Drilling
Recommended by LinkedIn
Why use useContext?
To share data globally without passing props manually.
When to use?
Example
import React, { createContext, useContext } from "react";
const ThemeContext = createContext();
function Child() {
const theme = useContext(ThemeContext);
return <h2>Theme: {theme}</h2>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<Child />
</ThemeContext.Provider>
);
}
export default App;
📌 Key Point: useContext replaces unnecessary prop passing.
7. useReducer – Advanced State Logic
Why use useReducer?
For complex state logic with multiple actions.
When to use?
Example
import React, { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
<h2>{state.count}</h2>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</>
);
}
export default Counter;
📌 Key Point: Use useReducer when useState becomes messy.
8. useLayoutEffect – DOM Measurements
Why use useLayoutEffect?
Runs before the browser paints the screen.
When to use?
Example
import React, { useLayoutEffect, useRef } from "react";
function Box() {
const boxRef = useRef();
useLayoutEffect(() => {
console.log(boxRef.current.offsetWidth);
}, []);
return <div ref={boxRef}>Hello</div>;
}
export default Box;
⚠️ Use sparingly — useEffect is preferred most of the time.
9. useImperativeHandle – Control Child from Parent
Why use useImperativeHandle?
Expose specific methods from child component.
When to use?
Example
import React, { useRef, forwardRef, useImperativeHandle } from "react";
const Input = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus() {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
});
function App() {
const ref = useRef();
return (
<>
<Input ref={ref} />
<button onClick={() => ref.current.focus()}>Focus</button>
</>
);
}
export default App;
10. useTransition – Smooth UI Updates (React 18)
Why use useTransition?
To keep UI responsive during heavy updates.
When to use?
Example
import React, { useState, useTransition } from "react";
function App() {
const [text, setText] = useState("");
const [isPending, startTransition] = useTransition();
function handleChange(e) {
startTransition(() => {
setText(e.target.value);
});
}
return (
<>
<input onChange={handleChange} />
{isPending && <p>Loading...</p>}
<p>{text}</p>
</>
);
}
export default App;
11. useDeferredValue – Delay Updates
Why use useDeferredValue?
Delay non-urgent UI updates.
When to use?
Example
import React, { useState, useDeferredValue } from "react";
function Search() {
const [query, setQuery] = useState("");
const deferredQuery = useDeferredValue(query);
return (
<>
<input onChange={(e) => setQuery(e.target.value)} />
<p>Searching for: {deferredQuery}</p>
</>
);
}
export default Search;
12. useId – Unique IDs (React 18)
Why use useId?
Generate unique IDs for accessibility.
When to use?
Example
import React, { useId } from "react";
function Form() {
const id = useId();
return (
<>
<label htmlFor={id}>Email</label>
<input id={id} />
</>
);
}
export default Form;
Final Advice
#React #ReactJS #JavaScript #WebDevelopment #FrontendDevelopment