1|Page
React JS Notes
What is State?
Definition:
State is a JavaScript object that holds information about the component’s current situation. When the state
changes, React re-renders the component to reflect the new data.
Example (Functional Component with useState):
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // state variable 'count' with initial value 0
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click Me
</button>
</div>
);
useState(0):
• Initializes state variable count with value 0
• setCount is a function used to update the value of count
Key Points:
• State is local to the component (unless lifted or shared).
• Changing state causes re-rendering.
• Managed using useState in functional components.
• In class components, state is managed via this.state and this.setState().
2|Page
What is setCount in React?
In this line:
const [count, setCount] = useState(0);
• count → is the state variable
• setCount → is the function to update that variable
How does it work?
When you call:
setCount(count + 1);
1. It updates the state value (count)
2. React re-renders the component to reflect the new value
Why can't we do count++ directly?
You should never mutate state directly like this:
count++; Wrong
count = 10; Wrong
Because:
• React won’t know the state changed
• Component won’t re-render
Instead, always use setCount:
setCount(count + 1); Correct
setCount should be setDispaly, setShow etc anything it will be.
What are Hooks in React?
Hooks are functions that let you “hook into” React state and lifecycle features in functional components.
Before Hooks, these features were only available in class components
Why Hooks?
Hooks were introduced in React 16.8 to:
• Use state and lifecycle methods in functional components
• Make components cleaner, reusable, and easy to test
• Avoid complex patterns like HOCs and render props
3|Page
Commonly Used Hooks
Hook Purpose
useState Adds state to functional components
useEffect Handles side effects (API calls, etc.)
useContext Access context API (global data)
useRef Access or manipulate DOM directly
useMemo Memoize expensive calculations
Example: useEffect
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = setInterval(() => setSeconds(s => s + 1), 1000);
return () => clearInterval(timer); // cleanup
}, []);
return <h2>Timer: {seconds}s</h2>;}
Rules of Hooks
1. Only call Hooks at the top level (not inside loops or conditions)
2. Only call Hooks from React functions (not normal JS functions)
How Add Multiple Condition?
1. Logical Operators (&&, ||)
Example with && (AND):
{isLoggedIn && hasPermission && <Dashboard />}
• If both isLoggedIn and hasPermission are true, then <Dashboard /> will render.
2. Ternary Operators (condition ? true : false)
Example:
{isAdmin? <AdminPanel /> : isUser ? <UserPanel /> : <GuestPanel />}
• Renders based on priority: Admin > User > Guest
4|Page
3. If-Else inside function body (JS block)
function MyComponent() {
if (!isLoggedIn) {
return <LoginPage />;
} else if (isAdmin) {
return <AdminPanel />;
} else {
return <UserPanel />; } }
4. Combining Conditions in JSX
{(user && user.isActive && user.role === "manager") && <ManagerDashboard />}
Example: Real Use Case
{isLoggedIn && (user.role === 'admin' || user.role === 'superuser') ? (<AdminPanel />) : ( <HomePage />)}
Where We Import Css File ?
1. Importing CSS in Component File
You can import a CSS file at the top of your component .js or .jsx file:
// MyComponent.jsx
import './MyComponent.css';
function MyComponent() {
return <div className="box">Hello!</div>;}
Make sure the CSS file is in the same folder or provide the correct relative path.
2. Import Global CSS in index.js or App.js
For global styles, import your main CSS (like index.css) at the top of your root files:
// index.js or App.js
import './index.css';
This style will apply globally across the entire app.
3. CSS in public Folder?
You can't directly import CSS from the public/ folder.
React doesn't process static files there.
If needed, add a <link> tag in public/index.html:
<link rel="stylesheet" href="%PUBLIC_URL%/styles.css" />
But it's not the React way — avoid this unless necessary.
5|Page
4. Importing External CSS (like Bootstrap)
Install Bootstrap:
npm install bootstrap
Then import it in index.js or App.js:
import 'bootstrap/dist/css/bootstrap.min.css';
5. CSS Modules (for scoped CSS)
If using CSS Modules, file name should be like MyComponent.module.css:
import styles from './MyComponent.module.css';
function MyComponent() {
return <div className={styles.box}>Box</div>;}
Summary Table
Type File Name Import in Usage
Component CSS MyComponent.css MyComponent.jsx .className
Global CSS index.css or app.css index.js Global across app
External CSS Bootstrap, etc. index.js Pre-built style frameworks
CSS Modules MyComponent.module.css MyComponent.jsx Scoped, modular styles
What are Props?
Props (short for properties) are read-only inputs that are passed from a parent component to a child
component.
Think of props as arguments passed to a function — they help you make components dynamic and reusable.
How do Props Work?
1. Passing Props
// ParentComponent.jsx
import Child from './Child';
function Parent() { return <Child name="Enamul" age={25} />;}
2. Receiving Props
// Child.jsx
function Child(props) { return (
<div>
<h2>Hello, {props.name}</h2>
<p>You are {props.age} years old</p>
</div> );}
6|Page
Example with Destructuring
Instead of props.name, you can do this:
function Child({ name, age }) {
return (
<div>
<h2>Hello, {name}</h2>
<p>You are {age} years old</p>
</div> );}
Key Points about Props
Feature Detail
Read-Only You cannot modify props inside child
Passed Downward From parent ➝ child, never upward
Dynamic You can pass data, functions, JSX, anything
Reusable Make components flexible and clean
Passing Functions as Props
function Parent() {
const greet = () => alert("Hello from Parent");
return <Child onClick={greet} />;}
function Child({ onClick }) {
return <button onClick={onClick}>Click Me</button>;}
Common Mistakes
• Trying to change props inside child:
props.name = "Hacked"; // Error
• Instead, use state in the parent to control and update the value, and pass it down.
What is a Controlled Component?
A controlled component is a form input element (like <input>, <textarea>, <select>) whose value is
controlled by React state.
It means React is the single source of truth for that input.
7|Page
Controlled vs Uncontrolled
Feature Controlled Component Uncontrolled Component
Value stored in React state DOM (via ref)
On change Uses onChange + setState Reads value using ref
Easy to validate Yes Hard
Recommended? Yes (for most cases) Only for simple quick tasks
Example of a Controlled Component
import React, { useState } from 'react';
function LoginForm() {
const [email, setEmail] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
alert(`Submitted Email: ${email}`); };
return (
<form onSubmit={handleSubmit}>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email" />
<button type="submit">Submit</button>
</form> );}
Breakdown:
• value={email} → React controls the input value
• onChange updates the state using setEmail
• No data lives inside the input tag directly — React controls everything
Why Use Controlled Components?
For validation (e.g., required fields, regex)
To dynamically enable/disable buttons
To update multiple fields in sync
To save data to backend easily
8|Page
useEffect Hook
What is useEffect?
useEffect is a React Hook that allows you to perform side effects in functional components.
Side Effects = Things that happen outside the normal flow of returning JSX.
Examples:
• API calls / Fetching data
• Updating DOM manually
• Setting up timers (setTimeout, setInterval)
• Listening to events (like resize, scroll)
• Subscribing / unsubscribing
Why useEffect is needed?
Before hooks, if you wanted side effects, you used class lifecycle methods, like:
• componentDidMount
• componentDidUpdate
• componentWillUnmount
useEffect replaces all of those in functional components, making code simpler and reusable.
Basic Syntax
import { useEffect } from "react";
useEffect(() => { // code to run (side-effect) }, [dependencies]);
Understanding with Examples
Run on every render
useEffect(() => {
console.log("Component rendered or updated");});
No dependency array ⇒ this runs after every render (initial + every update)
Run only once – on Mount (componentDidMount)
useEffect(() => {
console.log("Component mounted");}, []);
Empty dependency array [] ⇒ Runs only one time (when component loads)
Run when specific value changes (componentDidUpdate)
useEffect(() => {
console.log("Count changed:", count);}, [count]);
Runs only when count value changes.
9|Page
Cleanup Function (componentWillUnmount)
Used for removing timers, unsubscribing, clearing intervals, etc.
useEffect(() => {
const timer = setInterval(() => {
console.log("Running timer"); }, 1000);
return () => {
clearInterval(timer);
console.log("Cleanup done"); };}, []);
The function inside return is the cleanup that runs when the component is unmounted.
Summary Table
Dependency Array When useEffect Runs
No array After every render
[] (empty) Only on first render (mount)
[var1, var2] When any dependency changes
Common Interview Points
• useEffect combines componentDidMount, componentDidUpdate, and componentWillUnmount in
one hook.
• The cleanup function runs before the component is removed OR before running the effect again (if
dependencies changed).
• Avoid infinite loops by setting correct dependencies.
Interview Questions (with brief answers)
Q1. What is useEffect used for?
A: To perform side effects in functional components like API calls, timers, subscriptions, etc.
Q2. What happens if you don’t give a dependency array?
A: The effect runs after every render.
Q3. How do you mimic componentDidMount?
A: By passing an empty array [] as dependencies.
Q4. What is the purpose of return inside useEffect?
A: It is the cleanup function, used for unmounting or clearing.
Q5. Can we have multiple useEffect in one component?
A: Yes, absolutely! React allows multiple useEffect hooks and each handles different logic.
Practical Use Cases
• Fetching data from API on component load
• Listening to window resize
10 | P a g e
• Form validation on input changes
• Animation triggers
• Auto-save draft data
Example: Fetch data with useEffect
import React, { useState, useEffect } from "react";
function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(data => setUsers(data));
}, []);
return (
<div>
<h2>User List</h2>
{users.map(user => (
<p key={user.id}>{user.name}</p>
))}
</div> );}
Example: Updating Title on Count change
import React, { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count = ${count}`;
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div> );}
11 | P a g e
Loop in React (Rendering Lists with map())
In React, we do not use traditional for loops directly inside JSX.
Instead, we use the .map() method (a JavaScript array function) to loop and display elements.
Why use .map() in React?
• JSX wants to return something
• .map() returns a new array with transformed elements
• Perfect for rendering lists like menu items, cards, table rows, etc.
Basic Example
const numbers = [1, 2, 3, 4];
function NumbersList() {
return ( <div>
{numbers.map(num => (
<p key={num}>{num}</p>
))}
</div> );}
We looped through array and returned a <p> for each number.
Why key is important?
Whenever you loop in React, you MUST provide a unique key prop to each element.
✔ Helps React identify each item
✔ Avoids re-renders issues
✔ Key should be unique (id, index, etc.)
Looping array of objects
const users = [ { id: 1, name: "Enamul" }, { id: 2, name: "Nitesh" }, { id: 3, name: "Amit" }];
function UserList() {
return (
<ul>
{users.map(user => ( <li key={user.id}>{user.name}</li> ))}
</ul> );}
Rendering Components in a loop
function Card({ title }) {
return <div className="card">{title}</div>;}
function CardsScreen() {
const topics = ["HTML", "CSS", "React", "Node"];
12 | P a g e
return (
<div>
{topics.map((item, index) => (
<Card title={item} key={index} /> ))} </div> );}
Can we use for loop?
You can create an array manually using a for loop and then return it, but NOT inside return.
function Example() {
const items = [];
for (let i = 1; i <= 5; i++) { items.push(<p key={i}>Number: {i}</p>); }
return <div>{items}</div>;}
Bonus: Conditional Rendering + Loop
{items.map((item) => item.isActive ? <p key={item.id}>{item.name}</p> : null)}
Interview Tips on React Loops
• Use .map() for rendering multiple JSX elements.
• Always add key prop.
• Never write for loop directly inside JSX.
• Loop must return something.
Memory Table for Quick Revision
Concept Rule / Use
Main method array.map()
Inside return? Yes, with curly braces {}
Key prop Must be unique per item
for loop usage Outside return, store in array, then render
Mini Interview Questions
Q1. How do you render a list in React?
A: By using .map() function inside JSX and returning elements with a unique key.
Q2. Why is key prop important in loops?
A: Key helps React identify which elements changed, updated or removed for efficient rendering.
Q3. Can a simple for loop be used directly inside JSX?
A: No, JSX cannot have for blocks; instead, do it outside or use .map().
13 | P a g e
useRef Hook
What is useRef?
useRef is a React Hook that allows us to:
1. Access DOM elements directly
2. Store mutable values that can change without causing re-render
It returns a plain JavaScript object like this:
{ current: ... }
Syntax
import { useRef } from 'react';
const nameRef = useRef(initialValue);
Common Uses of useRef
1. Access / Focus DOM Elements
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();}
return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</div>);
Here, inputRef.current gives direct DOM access to input element.
2. Store a Value without Re-render
const countRef = useRef(0);
function increase() {
countRef.current = countRef.current + 1;
console.log(countRef.current);}
Changing countRef.current does not re-render the component like useState does.
3. Store Previous Value
const [count, setCount] = useState(0);
const prevCountRef = useRef();
useEffect(() => { prevCountRef.current = count;});
return (
14 | P a g e
<div>
<p>Current: {count}</p>
<p>Previous: {prevCountRef.current}</p>
</div>);
Difference between useRef(), useState() and useEffect()
Hook Re-render on change? Use Case
useState Yes UI updates, reactivity
useRef No Reference elements, store values silently
useEffect -- run side effects after render
⚠ Important Notes
• useRef does not trigger re-render when its value changes.
• It returns the same object on every render (.current persists).
• Mainly used for imperative actions like focus, scrolling, etc.
Real Interview Points
• useRef is the functional component replacement for createRef.
• It combines both features: storing data & accessing DOM.
• It’s often used for:
o focusing input automatically
o storing interval IDs
o storing previous prop/state values
o skipping re-render
Simple Example: Auto focus input on page load
import { useRef, useEffect } from "react";
function AutoFocusInput() {
const inputElement = useRef(null);
useEffect(() => { inputElement.current.focus(); }, []);
return <input ref={inputElement} type="text" placeholder="Type here..." />;}
When to NOT use useRef?
• Don’t use it to manage UI state that should re-render (use useState for that).
• Don't mutate state variables directly via ref.
15 | P a g e
Interview QnA (Quick)
1. What is useRef hook?
It returns a mutable object used to access DOM elements directly or hold a value that persists without
causing re-render.
2. Difference between useState vs useRef?
useState causes re-render on change; useRef does not.
3. Can we store previous value of state?
Yes, with useRef in combination with useEffect.
4. Alternative to useRef in class components?
React.createRef()
Uncontrolled Component in React
What is an Uncontrolled Component?
An uncontrolled component is a form input element (like input, textarea) whose value is handled by the
DOM itself, not by React state.
That means:
• We don’t use useState to store each value.
• We access the value only when needed using useRef or direct DOM.
Think of uncontrolled components like normal HTML forms — browser manages the input value.
KEY POINT: useRef + defaultValue
<input type="text" ref={inputRef} defaultValue="Hello" />
Example of Uncontrolled Component
import React, { useRef } from "react";
function FormUncontrolled() {
const nameRef = useRef(null);
function handleSubmit(e) {
e.preventDefault();
alert("Name: " + nameRef.current.value); }
return ( <form onSubmit={handleSubmit}>
<input type="text" ref={nameRef} />
<button type="submit">Submit</button>
</form> );}
• Here we didn't use useState
• No binding with value={...}
• We accessed value using nameRef.current.value only on submit
16 | P a g e
Features of Uncontrolled Components
Feature Uncontrolled Component
Manages value DOM (Browser)
Controlled by React state? No
Use of useState? Not required
Use of useRef? Yes, mostly used to access value
Real-time validation? Harder or manual
When used? Simple forms, quick temp inputs, legacy code
Controlled vs Uncontrolled (Difference Table)
Aspect Controlled Component Uncontrolled Component
Form data stored in React state DOM (via ref)
Real-time control Easy (value changes re-render) Harder
Uses useState? Yes No
Uses useRef? Optional (rare) Yes (to access value)
Performance Slightly lower (more renders) Faster (less re-rendering)
Examples <input value={value} onChange={...} /> <input ref={inputRef}
defaultValue="" />
Why called “Uncontrolled”?
Because React is not controlling the input’s value –
It depends on the native DOM to control the input.
Benefits
• Simpler for small forms
• Less code if you don’t need validation
• Slightly better performance
Drawbacks
• Hard to validate or manipulate in real-time
• Hard to trigger UI updates on change
• Less common in modern React apps
Real Interview Questions
1. What is an uncontrolled component in React?
A component where form data is handled by the DOM itself, not by React state.
17 | P a g e
2. How do you access the value of an uncontrolled input?
Using useRef and reading current.value.
3. Difference between controlled and uncontrolled component?
Controlled uses React state, uncontrolled depends on DOM using ref.
React.forwardRef (Forward Ref)
What is Forward Ref?
Normally, refs cannot be passed through a component to reach a child DOM element directly.
Forward Ref is a technique that allows us to pass ref from parent down to a child component, so that parent
can get direct access to the DOM element created inside child.
React provides a built-in function:
const MyComponent = React.forwardRef((props, ref) => { // ...});
Why do we need forwardRef?
When you have a custom component (child) wrapping an input or button, the parent can’t directly access that
inner input using ref.
Example problem without forwardRef:
function InputChild() {
return <input type="text" />;}
function Parent() {
const inp = useRef();
return (
<div> <InputChild ref={inp} /> // This will NOT work. ref is undefined here </div> );}
Here, the ref does not reach the actual <input>.
Solution: React.forwardRef
const InputChild = React.forwardRef((props, ref) => { return <input type="text" ref={ref} />;});
function Parent() { const inputRef = useRef();
function focusInput() {
inputRef.current.focus();
} return ( <div>
<InputChild ref={inputRef} />
<button onClick={focusInput}>Focus</button>
</div> );}
Now the ref from Parent will point to the actual input element inside child.
18 | P a g e
Syntax Summary
const ComponentName = React.forwardRef((props, ref) => {
return <element ref={ref} />;
});
Uses / Real-life uses
• Custom Input Components (like for UI libraries)
• Reusable Input or Button components
• Passing focus or scroll control from parent
• For integrating with third-party libraries
⚠ Important Points (Asked in Interview)
• forwardRef only works with functional components.
• It takes a function with (props, ref) as parameters.
• The forwarded ref can be used in parent to access DOM.
• If you need both ref and props, you must wrap the component.
React 18 vs React 19?
There is no syntax change for forwardRef in React 19, same as React 18. Only difference is potential type
support with TypeScript. Core concept remains same.
Interview QnA Quick
Q1. Why can’t we normally use ref on child component?
Because refs only work directly on DOM elements, not on custom components.
Q2. How do we solve it?
By using React.forwardRef() so that ref passed from parent goes to the child DOM element.
Q3. What arguments does forwardRef take?
A function with (props, ref).
useTransition
What is useTransition?
useTransition is a React hook that helps you manage UI transitions without blocking the main UI.
It lets you mark certain updates as low priority (like filtering a big list) so that more important updates like
typing, clicking, UI response feel smooth.
19 | P a g e
Simple Meaning:
useTransition = “Make some state updates non-urgent, so UI doesn’t lag or freeze”
Syntax
import { useTransition } from 'react';
const [isPending, startTransition] = useTransition();
• startTransition(() => {...}) ⇒ wrap slow or heavy updates inside this
• isPending ⇒ boolean, true while the transition is running
Why useTransition?
Imagine you have a big list (10000 items).
When user types in a search box, filtering is slow and causes typing lag.
To fix it, wrap the heavy filtering inside startTransition.
Example Usage
Without useTransition (laggy UI):
const [input, setInput] = useState('');
const [list, setList] = useState(largeArray);
const handleChange = (e) => { setInput(e.target.value);
setList(largeArray.filter(item => item.includes(e.target.value)));};
With useTransition (smooth typing):
const [input, setInput] = useState('');
const [list, setList] = useState(largeArray);
const [isPending, startTransition] = useTransition();
function handleChange(e) {
const value = e.target.value;
setInput(value);
startTransition(() => {
const filtered = largeArray.filter(item => item.includes(value));
setList(filtered); });}
Summary Table
Property Description
startTransition Function to mark an update as low priority
isPending Boolean flag to check if transition is in progress
Typical Use-case Filtering, searching, expensive calculations
20 | P a g e
Benefits
• Keeps UI smooth
• Improves user experience
• Doesn’t block urgent updates (like typing)
⚠ Things to Remember
• Only works in React 18 or above
• Perfect for heavy updates, search filters, dynamic lists
• isPending can be used to show loading spinners or skeletons
🗣 Interview Questions
1. What problem does useTransition solve?
o It prevents UI from blocking when non-urgent updates happen.
2. Which React version introduced useTransition?
o React 18 (in concurrent features)
3. What does startTransition do?
o It wraps state updates to make them low-priority.
4. How can you show the user that transition is still running?
o Using isPending to conditionally show "Loading..." or skeleton.
useFormStatus() Hook
Note: useFormStatus is not a standard React hook available in plain React apps.
It is part of React DOM 18.2+ and especially used in Next.js App Router.
What is useFormStatus?
useFormStatus is a hook that allows you to check:
• whether a form is currently submitting
• if the submission succeeded or failed
• and to disable buttons, show loaders during form actions
Use Case
When you have a form that submits data (like login form, API action), you can use useFormStatus() in child
components (like a Submit button) to automatically know if the form is in "pending" / "submitting" state.
This way you can show Loading..., disable button, or show success message.
21 | P a g e
Syntax Basics
"use client";
import { useFormStatus } from 'react-dom';
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button> );}
How does it work?
1. useFormStatus must be used inside a form component hierarchy.
2. Only works with server actions or form actions in Next.js.
3. It gives an object like:
{ pending, data, method, action }
Most important property:
Property Description
pending true when form is submitting
data FormData object (fields + values)
method HTTP method: 'POST', 'GET', etc.
action The form action URL or function
Simple Example (Next.js App Router)
// submit-form.js
"use client";
import { useFormStatus } from "react-dom";
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Sending..." : "Send"}
</button> );}
export default function ContactForm() {
async function sendData(formData) {
22 | P a g e
// server action
console.log(formData.get("name")); }
return (
<form action={sendData}>
<input type="text" name="name" />
<SubmitButton />
</form> );}
Observations
• When the form is submitting, pending = true
• We disabled button and show loader text
• It makes UI feel modern and user-friendly
Interview / Checklist
• useFormStatus is part of React DOM & mostly used in Next.js with app router & server actions
• It tells you whether a form is in pending state
• Very useful for UX
• You can only use it inside form components, not in random components
• It must be on client side component ("use client")
One Line Memory Tip
useFormStatus = "check if form is submitting"
Difference Between useTransition and useFormStatus
Feature / useTransition (React) useFormStatus (React DOM / Next.js)
Purpose
Main Goal Handle slow state updates without Track form submission state (pending or not)
blocking UI
Works in Any React app (React 18+) Primarily Next.js App Router with server actions
Usage For filtering, searching, heavy For disabling submit buttons, showing
computations “Submitting…” loaders
Returns [isPending, startTransition] array { pending, data, method, action } object
Triggers? Starts manually using startTransition() Automatically when form is submitted
Requires No No, but must be inside a <form> context
useRef?
Use-case Typing + filtering large lists Contact form submit button disabled while
example sending data
23 | P a g e
Conceptual Summary:
• useTransition
→ You decide which update is non-urgent.
→ You wrap heavy code inside startTransition(...).
• useFormStatus
→ You do not call it. It auto detects a <form> submission.
→ Just checks if form is "pending" (submitting) and updates UI (button disable, loader, etc).
Code Comparison
useTransition (manual)
const [isPending, startTransition] = useTransition();
function handleChange(value) {
startTransition(() => {
heavyFilter(value); });}
useFormStatus (form-based)
import { useFormStatus } from 'react-dom';
function SubmitBtn() {
const { pending } = useFormStatus();
return ( <button type="submit" disabled={pending}> {pending ? "Submitting…" : "Submit"} </button> );}
Easy One-Liner
✔ useTransition → manual slow updates
✔ useFormStatus → automatic form submission detection
Pure Component vs Impure (Normal) Component
React has two types of class components (in older/class-based React):
1. Regular/Impure Component (React.Component)
2. Pure Component (React.PureComponent)
Note: In functional components, this concept is similar to React.memo.
What is a Pure Component?
A Pure Component automatically prevents unnecessary re-rendering.
It does a shallow comparison of props and state.
• If props/state didn’t change → it skips re-render
• This improves performance
We use:
class Demo extends React.PureComponent {}
24 | P a g e
What is an Impure (Regular) Component?
A Regular Component (React.Component) re-renders every time its parent re-renders — even if props did not
change.
It doesn’t compare previous and new values.
class Demo extends React.Component {}.
Main Differences
Feature PureComponent Component (Impure)
Re-rendering Only if state/props changed (shallow) On every update (even unchanged)
ShouldComponentUpdate Already implemented internally We need to implement it manually
Used for Performance optimization Normal components
Functional Equivalent React.memo Normal functional component
Example:
class A extends React.PureComponent {
render() { console.log("Pure Component Rendered"); return <h1>{this.props.name}</h1>; }}
class B extends React.Component {
render() {
console.log("Regular Component Rendered");
return <h1>{this.props.name}</h1>;}}
// If parent re-renders with same props:
// A will NOT re-render
// B WILL re-render
⚠ Important Note
PureComponent only does shallow comparison. If props are objects/arrays and change by reference, it will re-
render.
For Functional Components
• PureComponent ≈ React.memo(MyComponent)
• Component ≈ normal function component
When to use PureComponent?
• When your component gets the same props often
• To improve performance by avoiding useless renders
• But it should not use complex nested objects as props
25 | P a g e
Interview Questions Summary
• Q. What is PureComponent?
→ A class component that does shallow comparison of props/state and avoids unnecessary renders.
• Q. Difference with normal Component?
→ Regular component does not compare props, so it always re-renders.
• Q. Functional Alternative of PureComponent?
→ React.memo()
One-liner Memory:
PureComponent = Smart component that skips re-renders unless data changes.
What is Derived State in React?
Derived state is state that is calculated from props or other state, not stored directly.
Instead of keeping a duplicate value in state, we derive that value using logic.
Why avoid derived state when possible?
Because keeping multiple sources of truth leads to bugs!
• If you store the same info twice (state + props), they can get out of sync
• React docs recommend calculating when needed instead of storing
Example of BAD Derived State
function Example({ price }) {
const [taxedPrice, setTaxedPrice] = useState(price * 1.18);
// What if price prop changes? Our taxedPrice might become wrong unless we sync again.}
➡ This is bad because taxedPrice is derived from price, so better derive directly.
Good way (No derived state)
function Example({ price }) {
const taxedPrice = price * 1.18; // derived on the fly
return <p>Price with Tax: {taxedPrice}</p>;}
When you MUST use derived state?
In some cases, yes, derived state is necessary:
• When you need to do expensive calculation only once (avoid recalculation)
• When you need a copy that user can modify separately
• Or use derived state and sync with useEffect:
function Example({ price }) {
const [taxedPrice, setTaxedPrice] = useState(0);
26 | P a g e
useEffect(() => { setTaxedPrice(price * 1.18); }, [price]); // keep syncing when price changes
return <p>Taxed Price: {taxedPrice}</p>}
Warning:
If you use derived state incorrectly, you'll face:
• Infinite loops
• Stale values
• Unexpected UI bugs
Key Points for Interviews:
• Derived state means storing values that are calculated from other state/props
• Prefer computing them during render instead of storing
• Use useEffect to sync derived state only if necessary
• Avoid duplication of logic or two sources of truth
Real Interview Question:
Why is derived state considered an anti-pattern sometimes?
Answer:
Because it risks making state out-of-sync with props, breaking React's single source of truth principle. Use
memoization (useMemo) or compute values directly while rendering.
One-Line Summary
Derived State = duplicate or computed state based on props/state — avoid storing it unless really needed.
What does "Lifting State Up" mean?
When two or more child components need to share or sync the same data/state, we move that state up to their
common parent component.The parent becomes the single source of truth, and passes data + functions down
via props.
Why do we lift state?
• To avoid mismatched data between siblings
• To keep data centralized
• So that children can communicate through the parent
Example Scenario
You have two components:
• Component A: an input field
• Component B: displays what user typed
Normally, both components don't know each other's state. So we lift the state up into their parent.
27 | P a g e
Code Example of Lifting State Up
import React, { useState } from "react";
// Child A
function InputChild({ handleChange }) {
return (
<input type="text" onChange={(e) => handleChange(e.target.value)} />
);}
// Child B
function DisplayChild({ text }) {
return <h3>User typed: {text}</h3>;}
// Parent
function ParentComponent() {
const [data, setData] = useState("");
function updateValue(val) {
setData(val); } return (
<div>
<InputChild handleChange={updateValue} />
<DisplayChild text={data} />
</div> );}
export default ParentComponent;
Summary in Plain Words
• State lives in Parent
• Child A updates Parent via function
• Parent passes updated data to Child B
• Both children are synced via Parent's state
Advantages of Lifting State Up
Benefit Description
Single source of truth Only one state, less bugs
Sibling communication One child sends data to another via parent
React recommended pattern Promotes unidirectional data flow
28 | P a g e
⚠ When NOT to lift state?
• If only one component uses that data
• If siblings don't need to share data
• Too much lifting makes parent very large (called Prop Drilling issue). In that case use Context API.
Interview Questions
Q1. What is lifting state up?
Answer: Moving shared state from child component(s) into their common parent so they can share data.
Q2. Why is it useful?
Answer: It prevents duplication of state and keeps the data consistent between child components.
Q3. What problem can occur if you lift too much state?
Answer: It leads to "prop drilling" and tightly coupled parent which becomes hard to maintain.
One-Line Memory
Lifting state up = Put data in parent so siblings can communicate & stay in sync.
Updating Object in React State
In React, you should never mutate state directly.
That means: don't do state.myObj.key = value;
Instead, you need to create a new copy of that object, update the copy, and then set the new object using
setState or setX.
Functional Component Example
Assume state is an object:
const [user, setUser] = useState({
name: "Enamul",
age: 25,
city: "Lucknow"
});
Correct way to update one property:
setUser((prevUser) => ({
...prevUser,
age: 26
}));
We use the spread operator (...) to copy previous object, then update the specific key.
29 | P a g e
Add new property to object:
setUser((prevUser) => ({
...prevUser,
profession: "Developer"}));
Wrong Way (mutation):
user.age = 26; // Wrong
setUser(user); // Still wrong because you mutated original
Example in Class Component
this.state = {
user: { name: "Amit", age: 22, city: "Delhi" }
};
// Later:
this.setState((prev) => ({
user: {
...prev.user,
city: "Mumbai"
}));
Updating Nested Object or Array inside State
If you have nested objects:
const [state, setState] = useState({
user: { name: "John", address: { city: "NY", pin: 123 } }
});
setState((prev) => ({
...prev,
user: {
...prev.user,
address: {
...prev.user.address,
city: "LA"
}}));
30 | P a g e
Key Interview Points
• Always treat state as immutable
• Use spread operator or Object.assign()
• Use callback version of setState or setX if updating based on previous value
• For arrays: use .map() or .filter() + spread
One line summary:
Updating object state in React = copy old object → change → set new object (never mutate directly)
✍ Quick MCQ
Q: Which one correctly updates object state?
a) user.age = 25; setUser(user);
b) setUser({ ...user, age: 25 })
Updating Arrays in React State
Just like objects, arrays in React state must not be mutated directly.
We should always create a new array and then call setState or setX.
Functional Component Example
const [items, setItems] = useState([1, 2, 3]);
Add / Push new value
Wrong (mutate):
items.push(4); //
setItems(items);
Correct:
setItems([...items, 4]);
Remove item
Remove by index or value using filter()
setItems(items.filter((item) => item !== 2));
Update item in array
Example: update an object in array or update value at index
setItems(items.map((item) => item === 2 ? 20 : item ));
31 | P a g e
Example with Array of Objects
const [users, setUsers] = useState([
{ id: 1, name: "Enamul" },
{ id: 2, name: "Nitesh" }
]);
// Update user name
setUsers(users.map(user =>
user.id === 2 ? { ...user, name: "Raghunath" } : user));
Full Add/Edit/Delete Example
// Add new object
setUsers([...users, { id: 3, name: "Amit" }]);
// Delete by id
setUsers(users.filter(u => u.id !== 1));
Key Rules (Important)
Goal Correct Method
Add [...oldItems, newItem]
Remove .filter()
Update/Replace .map()
Do NOT mutate original push, splice, sort
Why no direct mutation?
• It won't trigger React re-render
• React compares state by reference
• Mutation breaks immutability and can cause bugs
Bonus: Updating nested arrays
const [data, setData] = useState({
numbers: [1,2,3]
});
// add to inner array
setData(prev => ({
...prev,
numbers: [...prev.numbers, 4]}));
32 | P a g e
✍ Interview QnA
Q: How do you update an array in state?
→ By creating a new copy of array using spread, filter, or map, then updating with setState.
Q: Why can't we use push()?
→ Because push() mutates original array which React won't detect as a new state.
One-line Summary:
Always create a new array (spread/map/filter) instead of mutating while updating array in React state.
What is useActionState?
useActionState is a hook used to handle form submissions + server actions + state update in one step.
It simplifies:
• Form state handling
• Submitting data to a server function
• Updating UI with the result
This is typically used with server actions (like export async function action(formData) in Next.js 13/14 App
Router).
Syntax
const [state, action, isPending] = useActionState(asyncAction, initialState);
What each part means?
Part Meaning
initialState default value of state
asyncAction(formData, prevState) function that runs with form submit
state current state / result
action function used as form action
isPending boolean: true while form is submitting
When to use it?
• When submitting forms in Next.js App Router with server actions
• When you want to update state based on result of server action
• Simplify form + state logic without using useState + useFormStatus separately
Key Features
• You no longer need separate useState to store the result
• No need to manually manage loading state — isPending gives it
• Combines server action + client state nicely
33 | P a g e
Important Notes
• Only works in React DOM with server actions (Next.js App Router)
• Used in client component, but wraps a server function
• Not available in simple CRA or Vite React apps
Interview Style Points
• useActionState helps manage form state that depends on the result of an async server action.
• It returns an array: [state, actionFunction, isPending]
• Encourages progressive enhancement and simplicity in Next.js forms
One-line Memory
useActionState = useState + formAction + loader all in one hook (for server form submissions)
Quick Comparison
Hook Use Case
useState General local state in client app
useTransition For async UI transitions (no server connection)
useFormStatus Check if form submission is pending
useActionState Submit form + get result + auto state update
Custom Hooks in React
What is a Custom Hook?
A Custom Hook is basically a reusable function that uses other React hooks inside it (like useState, useEffect,
etc.) and follows the rules of hooks.
It helps you extract and reuse common logic between components.
It starts with the word use
It is NOT a component
It is just a function that may return data, functions or JSX
Why do we use Custom Hooks?
• To avoid code duplication
• To keep components clean
• To separate logic from UI
• To share features (like fetching logic, form logic, animation behavior) across multiple components
34 | P a g e
Example: Create a custom hook called useCounter
import { useState } from "react";
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
function increment() { setCount(prev => prev + 1); }
function decrement() {
setCount(prev => prev - 1); }
return { count, increment, decrement };}
export default useCounter;
Using the custom hook in any component
import useCounter from "./useCounter";
function CounterComponent() {
const { count, increment, decrement } = useCounter(5);
return ( <div>
<h2>Count: {count}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div> );}
Common Types of Custom Hooks
Use-case Example Hook Name
Fetch data from API useFetch, useFetchData
Form Input handling useInput, useForm
Window width tracking useWindowSize
Debounce search values useDebounce
Local Storage sync useLocalStorage
Another example: useFetch
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then(res => res.json()) .then(data => {
35 | P a g e
setData(data);
setLoading(false); });
}, [url]);
return { data, loading };}
export default useFetch;
Rules for Custom Hooks
• Must start with use
• Can call other hooks inside it
• Must follow Rules of hooks (only call at top-level, not inside loops or conditions)
Interview Q&A
Q1. What is a custom hook?
→ A reusable function that uses React hooks to share logic between components.
Q2. Why would you use a custom hook?
→ To remove duplicate logic and keep components simple.
Q3. Does a custom hook return JSX?
→ Usually No, it returns values or functions — but you can return JSX if needed (rare).
Q4. Can a custom hook call another custom hook?
→ Yes, they are just functions.
One line memory
Custom Hooks = Your own reusable React logic, wrapped in a function that starts with use.
React Context API
What is Context API?
React Context API is a built-in feature that allows you to share data globally across components without
passing props manually at every level.
It helps when multiple components need access to the same data (like user info, theme, language, authentication,
etc.)
Problem: Prop Drilling
Prop drilling = passing data from parent → child → grandchild → great-grandchild just to reach the last
component. This becomes messy in large apps.
Solution = Create a Context and provide data at top-level, then consume it anywhere.
36 | P a g e
Main Steps of Using Context
Step Description
1. Create context using createContext()
2. Wrap components inside a Context Provider
3. Consume it using useContext() or Context.Consumer
Code Example
Step 1: Create Context File
import { createContext } from "react";
const UserContext = createContext();
export default UserContext;
Step 2: Create Provider component
import React, { useState } from "react";
import UserContext from "./UserContext";
export default function UserProvider({ children }) {
const [user, setUser] = useState("Enamul");
return (
<UserContext.Provider value={{ user, setUser }}>
{children}
</UserContext.Provider> );}
Step 3: Wrap in App.js
import UserProvider from "./UserProvider";
import Dashboard from "./Dashboard";
function App() {
return (
<UserProvider>
<Dashboard />
</UserProvider> );}
Step 4: Consume Anywhere
import { useContext } from "react";
import UserContext from "./UserContext";
function Dashboard() {
const { user } = useContext(UserContext);
37 | P a g e
return <h1>Welcome, {user}!</h1>;}
Benefits of Context API
• Avoids prop drilling
• Central and clean state sharing
• Great for theme, auth, language, settings
⚠ When NOT to use it?
• Not a replacement for global state libraries (Redux, Zustand)
• Not good for very frequent updates (like big forms)
• Too many contexts can cause re-renders
React Interview Questions on Context API
Q1. What problem does Context API solve?
→ Avoids prop drilling — allows passing data to deeply nested components.
Q2. How do you consume context in a functional component?
→ Using useContext(MyContext).
Q3. What alternative to Context for global state?
→ Redux, Zustand, Recoil, MobX, etc.
Summary Table
Concept Meaning
createContext() Create context object
Provider Supplies the data to children
useContext hook Access context value easily in functional components
Prop Drilling Passing props layer-by-layer unnecessarily
One-Line Memory Hack:
Context = "Global data provider" inside React, to avoid passing props manually.
38 | P a g e
React Router — Router vs Routes vs Route
React Router is a library used for navigation between pages or components in a React app.
In React Router v6 (latest), we mainly use:
• <BrowserRouter>
• <Routes>
• <Route>
Let’s break each one:
<BrowserRouter> (also called Router)
• The main parent component that wraps the whole app
• It enables routing functionality in your app
• It listens to URL changes
import { BrowserRouter } from 'react-router-dom';
<BrowserRouter>
<App />
</BrowserRouter>
<Routes>
• It acts like a container for all individual routes
• It replaces old <Switch> in v6
• It allows only the first matching <Route> to render
<BrowserRouter>
<Routes>
// all <Route> goes here
</Routes>
</BrowserRouter>
<Route>
• It defines the actual path and the component to show
• Syntax: <Route path="/somepath" element={<ComponentName />} />
Example:
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
Simple Full Example
39 | P a g e
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./Home";
import About from "./About";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter> );}
Summary Table
Concept Use / Role
BrowserRouter Wraps whole app; enables routing
Routes Wrapper for all Route definitions
Route Associates a URL path to a component
BONUS: Link Component
To navigate without reloading page, we use:
import { Link } from 'react-router-dom';
<Link to="/about">About</Link>
⚠ Common Beginner Confusion
Old React Router v5 New v6 (latest)
<BrowserRouter> Same
<Switch> replaced by <Routes>
<Route component={Home} /> now <Route element={<Home />} />
Interview style memory hack:
BrowserRouter gives routing power,
Routes groups the paths,
Route defines each path with a component