🔹 Topic 1: React Components & Props
📖 Explanation
● Component = Reusable piece of UI (like a function returning JSX).
● Types of Components:
○ Functional Components (modern, use hooks).
○ Class Components (older, not common in Next.js).
● Props = Inputs to a component. Props are:
○ Read-only (immutable).
○ Passed from parent → child.
🖥 Example
// Greeting.js
function Greeting({ name, age }) {
return <h2>Hello {name}, you are {age} years old!</h2>;
}
// App.js
export default function App() {
return (
<div>
<Greeting name="Rifat" age={22} />
<Greeting name="Thomas" age={25} />
</div>
);
}
✅ Output:
Hello Rifat, you are 22 years old!
Hello Thomas, you are 25 years old!
❓ Interview-Level Q&A
Q1: What is a React component?
Answer:
A React component is a reusable, independent UI block written in JavaScript/JSX that can
accept inputs (props) and return React elements. Components allow modular development and
improve maintainability.
Q2: Difference between Functional and Class Components?
Answer:
● Functional Component: Simple JS function, uses hooks for state & lifecycle. Preferred
in modern React (and Next.js).
● Class Component: ES6 class, uses this.state and lifecycle methods
(componentDidMount, etc.). Rare in new codebases.
Q3: What are Props in React?
Answer:
Props (short for properties) are inputs passed from parent to child components. They are
immutable inside the child, ensuring unidirectional data flow.
Q4: Can you modify props inside a component?
Answer:
No. Props are read-only. If you need to change data, use state inside the component or lift
state up to the parent.
Q5: Why are components reusable?
Answer:
Because a component’s UI and logic are isolated. You can pass different props to the same
component and get different outputs without rewriting code.
🔹 Topic 2: JSX & Rendering
📖 Explanation
● JSX = JavaScript XML.
It lets us write HTML-like syntax inside JavaScript.
● Behind the scenes, JSX is converted into React.createElement() calls.
● JSX allows dynamic rendering using {} (to embed JS expressions).
● JSX must return a single parent element.
🖥 Example
function App() {
const name = "Rifat";
const isLoggedIn = true;
return (
<div>
<h1>Hello, {name} 👋</h1>
<p>{isLoggedIn ? "Welcome back!" : "Please log in"}</p>
</div>
);
}
export default App;
✅ Output:
Hello, Rifat 👋
Welcome back!
⚡ JSX Rules
1. Must return one root element.
(Use <div> or <></> as a wrapper).
2. Use camelCase for attributes:
○ className instead of class.
○ onClick instead of onclick.
3. Expressions in {} (no statements like if, for).
4. Use fragments <>...</> if you don’t want extra <div>.
❓ Interview-Level Q&A
Q1: What is JSX in React?
Answer:
JSX stands for JavaScript XML. It is a syntax extension that allows writing HTML-like code in
JavaScript. JSX makes the UI more declarative and easier to understand.
Q2: Why do we use JSX instead of plain JavaScript?
Answer:
● Cleaner syntax.
● Easier to visualize the UI structure.
● React’s rendering logic (via React.createElement) is automatically handled.
Q3: What are the rules of JSX?
Answer:
1. Must return a single parent element.
2. Attributes use camelCase (className, htmlFor).
3. JS expressions inside {} only.
4. Use fragments when extra wrappers are not needed.
Q4: Can JSX be written without Babel?
Answer:
Yes, but it’s difficult. Browsers don’t understand JSX directly—it must be compiled into
React.createElement() calls. Babel or TypeScript handles this automatically.
Q5: How does JSX prevent injection attacks (XSS)?
Answer:
React automatically escapes values embedded in JSX. So if you insert user input like
{userInput}, React will render it as text, not HTML or script—preventing XSS.
🔹 Topic 3: State (useState)
📖 Explanation
● State = Data that changes over time inside a component.
● Unlike props (external inputs), state is internal & mutable.
● In functional components, we use the useState hook.
const [value, setValue] = useState(initialValue);
● value → current state.
● setValue → function to update state.
● Updating state re-renders the component.
🖥 Example 1: Counter
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>➕ Increase</button>
<button onClick={() => setCount(count - 1)}>➖ Decrease</button>
</div>
);
}
export default Counter;
✅ Output: Clicking buttons updates count dynamically.
🖥 Example 2: Toggle Button
function Toggle() {
const [isOn, setIsOn] = useState(false);
return (
<button onClick={() => setIsOn(!isOn)}>
{isOn ? "ON" : "OFF"}
</button>
);
}
⚡ Key Points
1. State updates are asynchronous → React may batch multiple updates.
2. Always use the setter function (setState), never mutate directly.
❌ count++ → Wrong
✅ setCount(count + 1) → Correct
3. If new state depends on old state → use functional update:
setCount(prev => prev + 1);
❓ Interview-Level Q&A
Q1: What is the difference between state and props?
Answer:
● Props: Passed from parent to child, read-only, external.
● State: Managed inside a component, mutable, internal.
Q2: Why is state immutable in React?
Answer:
Directly mutating state won’t trigger a re-render. Using the setState function ensures React
knows the value changed and re-renders correctly.
Q3: What happens when you update state in React?
Answer:
1. React schedules a re-render.
2. The component function runs again with the new state value.
3. The DOM is updated efficiently using Virtual DOM diffing.
Q4: What is the difference between setCount(count + 1) and
setCount(prev => prev + 1)?
Answer:
● setCount(count + 1) → Uses the value of count at that moment.
● setCount(prev => prev + 1) → Uses the latest state (safe for multiple updates in
the same render).
Q5: Can you use state in class components?
Answer:
Yes, in class components you use this.state and this.setState().
But in functional components, we use useState. Next.js projects almost always use functional
components.
🔹 Topic 4: Events & Handlers in React
📖 Explanation
● React events work similar to DOM events, but use camelCase (onClick, onChange).
● You pass a function as the event handler.
● Event handlers receive a SyntheticEvent (React’s wrapper around browser events for
cross-browser support).
🖥 Example 1: Button Click
function ButtonClick() {
function handleClick() {
alert("Button clicked!");
}
return <button onClick={handleClick}>Click Me</button>;
}
🖥 Example 2: Input Change
import { useState } from "react";
function InputExample() {
const [text, setText] = useState("");
return (
<div>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<p>You typed: {text}</p>
</div>
);
}
⚡ Key Points
1. Event names use camelCase → onClick, onSubmit, onChange.
2. Must pass a function reference, not call it directly.
○ ❌ onClick={handleClick()}
○ ✅ onClick={handleClick}
3. To pass arguments → wrap inside arrow function:
<button onClick={() => handleClick("Hello")}>Click</button>
4. Use event.preventDefault() to stop default behavior (e.g., form submit reload).
❓ Interview-Level Q&A
Q1: How are React events different from HTML DOM events?
Answer:
● React uses SyntheticEvents for cross-browser compatibility.
● Event names use camelCase (onClick vs onclick).
● In JSX, you pass a function, not a string.
Q2: Why do we often use arrow functions in event handlers?
Answer:
Arrow functions allow:
1. Passing arguments (onClick={() => handleClick(id)}).
2. Binding this automatically (in class components).
Q3: What is event delegation in React?
Answer:
React attaches event listeners at the root (document level) and delegates them internally.
This improves performance instead of attaching listeners to every element.
Q4: What is event.preventDefault() and when to use it?
Answer:
It prevents the browser’s default action.
Example: Preventing form from refreshing page on submit.
function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log("Form submitted!");
}
return <form onSubmit={handleSubmit}><button>Submit</button></form>;
}
Q5: Can you pass parameters to event handlers in React?
Answer:
Yes, using an arrow function:
<button onClick={() => handleClick(5)}>Click</button>
🔹 Topic 5: Conditional Rendering in
React
📖 Explanation
● Conditional rendering = Displaying UI based on a condition.
● In React, we use JavaScript expressions (if, ternary ? :, logical &&) inside JSX.
🖥 Example 1: Using if/else
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h2>Welcome back! 🎉</h2>;
}
return <h2>Please log in</h2>;
}
🖥 Example 2: Using Ternary Operator
function Greeting({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <h2>Welcome back! 🎉</h2> : <h2>Please log
in</h2>}
</div>
);
}
🖥 Example 3: Using && (logical AND)
function Notification({ unread }) {
return (
<div>
<h1>Inbox</h1>
{unread > 0 && <p>You have {unread} new messages</p>}
</div>
);
}
⚡ Key Points
1. Ternary (? :) is best when you need two possible outputs.
2. && is best when you need to show something only if condition is true.
3. You can also assign conditions before return to keep JSX clean.
❓ Interview-Level Q&A
Q1: What are different ways to do conditional rendering in React?
Answer:
1. if/else statements.
2. Ternary operator (condition ? A : B).
3. Logical AND (condition && A).
4. Using variables before JSX to decide what to render.
Q2: When should you use && vs ? : for conditional rendering?
Answer:
● Use && when you only want to show something if true.
● Use ? : when you need two options (true vs false).
Q3: How do you handle authentication with conditional rendering?
Answer:
Render different UI based on login state. Example:
{isLoggedIn ? <Dashboard /> : <Login />}
Q4: What happens if condition is false with && in React?
Answer:
React ignores false and renders nothing. Example:
false && <p>This will not render</p>
Q5: Can you use functions for conditional rendering?
Answer:
Yes. You can write a helper function:
function renderMessage(isLoggedIn) {
return isLoggedIn ? "Welcome back!" : "Please log in";
}
<p>{renderMessage(true)}</p>
🔹 Topic 6: Lists & Keys in React
📖 Explanation
● In React, we often need to render lists of data (from arrays, APIs, etc.).
● Use .map() to loop and return JSX.
● Keys help React identify elements → so it can update efficiently when list changes.
● Keys must be unique among siblings, usually use id.
🖥 Example 1: Simple List
function TaskList() {
const tasks = ["Learn React", "Learn Next.js", "Build Projects"];
return (
<ul>
{tasks.map((task, index) => (
<li key={index}>{task}</li>
))}
</ul>
);
}
🖥 Example 2: List with Unique IDs
function UserList() {
const users = [
{ id: 1, name: "Rifat" },
{ id: 2, name: "Thomas" },
{ id: 3, name: "Alice" }
];
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
⚡ Key Points
1. Keys must be unique & stable → don’t use array index if data can change.
2. Without keys, React re-renders inefficiently (may re-build the whole list).
3. Keys don’t get passed as props (React uses them internally).
❓ Interview-Level Q&A
Q1: Why are keys important in React lists?
Answer:
Keys help React identify which items changed, added, or removed. This makes rendering
efficient by reusing existing DOM nodes instead of re-creating them.
Q2: What happens if you don’t provide keys?
Answer:
React falls back to using array index → this can cause bugs (wrong items update) and poor
performance.
Q3: Why should you avoid using index as a key?
Answer:
If the list order changes, React may confuse items (e.g., updating wrong component state).
Index as key is safe only for static lists that never change.
Q4: Are keys accessible inside the child component?
Answer:
No. Keys are only used internally by React’s reconciliation algorithm. They are not passed as
props.
Q5: How does React’s reconciliation algorithm use keys?
Answer:
● React compares the old list with the new list.
● If keys match → reuses the element.
● If keys differ → removes old & creates new element.
🔹 Topic 7: useEffect (Side Effects &
Data Fetching)
📖 Explanation
● React renders UI → but sometimes we need side effects (code outside rendering).
● Examples of side effects:
○ Fetching data from API.
○ Setting up subscriptions / event listeners.
○ Updating document.title.
● In functional components → we use useEffect.
useEffect(() => {
// side effect code
return () => {
// cleanup (optional)
}
}, [dependencies]);
● dependencies → tells React when to re-run effect.
🖥 Example 1: Run on Every Render
import { useEffect } from "react";
function App() {
useEffect(() => {
console.log("Component rendered or updated!");
});
return <h1>Hello</h1>;
}
🖥 Example 2: Run Once (on Mount)
import { useEffect } from "react";
function App() {
useEffect(() => {
console.log("Runs only once, like componentDidMount");
}, []); // empty array → runs only once
return <h1>Welcome</h1>;
}
🖥 Example 3: Data Fetching
import { useEffect, useState } from "react";
function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(data => setUsers(data));
}, []); // run once
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
🖥 Example 4: Cleanup (Remove Listener)
import { useEffect } from "react";
function WindowResize() {
useEffect(() => {
const handleResize = () => console.log("Resized!");
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return <h1>Check console on resize</h1>;
}
⚡ Key Points
1. No dependencies → runs on every render.
2. Empty dependencies [] → runs only once.
3. Dependencies [x, y] → runs whenever x or y changes.
4. Always clean up (unsubscribe listeners, clear timers) to avoid memory leaks.
❓ Interview-Level Q&A
Q1: What is useEffect used for?
Answer:
useEffect is used to perform side effects (like fetching data, subscriptions, timers, DOM
updates) after rendering.
Q2: Difference between useEffect with [] and without []?
Answer:
● Without [] → runs after every render.
● With [] → runs only once (on mount).
● With [deps] → runs when dependency changes.
Q3: What is the cleanup function in useEffect?
Answer:
It’s a function returned inside useEffect that runs when the component unmounts or before
re-running the effect. Used for cleanup like removing listeners.
Q4: Difference between useEffect and lifecycle methods in class
components?
Answer:
● componentDidMount → useEffect(() => {}, [])
● componentDidUpdate → useEffect(() => {}, [deps])
● componentWillUnmount → cleanup inside useEffect
Q5: What happens if you forget cleanup in useEffect?
Answer:
It can cause memory leaks, duplicate event listeners, or stale data updates.
🔹 Topic 8: Props Drilling vs Context API
📖 Explanation
🔸 Props Drilling
● Props drilling happens when you pass data through multiple layers of components
just so a deeply nested component can use it.
● This makes code messy and hard to maintain.
Example of props drilling 👇
function Child({ user }) {
return <h2>Hello, {user}</h2>;
}
function Parent({ user }) {
return <Child user={user} />;
}
export default function App() {
return <Parent user="Rifat" />;
}
Here, user is passed through Parent only to reach Child.
🔸 Context API
● The Context API is React’s built-in solution for avoiding props drilling.
● We create a Context, provide a value at a high level, and consume it anywhere below in
the tree.
🖥 Example: Context API
import { createContext, useContext } from "react";
// 1. Create context
const UserContext = createContext();
// 2. Create provider
function App() {
return (
<UserContext.Provider value="Rifat">
<Parent />
</UserContext.Provider>
);
}
function Parent() {
return <Child />;
}
// 3. Consume context
function Child() {
const user = useContext(UserContext);
return <h2>Hello, {user}</h2>;
}
export default App;
✅ Output:
Hello, Rifat
Now, no props drilling needed 🚀
⚡ Key Points
1. Use props for small/local data sharing.
2. Use Context API for global state (auth, theme, language, user info).
3. Too much Context → can cause unnecessary re-renders. For big apps, use Redux /
Zustand instead.
❓ Interview-Level Q&A
Q1: What is props drilling in React?
Answer:
Props drilling is when data is passed down through multiple levels of components
unnecessarily, just so a deeply nested component can access it.
Q2: How does the Context API solve props drilling?
Answer:
The Context API provides a global data store that any child component can consume without
manually passing props through each parent.
Q3: Difference between Props and Context?
Answer:
● Props: Explicit, component-specific, one-way data flow.
● Context: Global, avoids drilling, good for shared state.
Q4: When should you avoid Context API?
Answer:
When state changes frequently (e.g., live chat messages) → Context may cause too many
re-renders. Better to use state management libraries like Redux or Zustand.
Q5: How do you consume context in a component?
Answer:
Using useContext hook.
const value = useContext(MyContext);
🔹 Topic 9: Forms & Controlled
Components
📖 Explanation
In React, handling forms is different than plain HTML because React manages the state of form
inputs.
🔸 Controlled Components
● A form input whose value is controlled by React state.
● We use useState to store input values and onChange to update them.
🖥 Example: Controlled Input Form
import { useState } from "react";
export default function FormExample() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
alert(`Name: ${name}, Email: ${email}`);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>Name: </label>
<input
type="text"
value={name} // controlled by state
onChange={(e) => setName(e.target.value)}
/>
</div>
<div>
<label>Email: </label>
<input
type="email"
value={email} // controlled by state
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<button type="submit">Submit</button>
</form>
);
}
✅ The input values are always in sync with React state.
🔸 Uncontrolled Components
● Input values are handled by the DOM itself, not React state.
● We use useRef to access them.
import { useRef } from "react";
export default function UncontrolledForm() {
const inputRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
alert(`Input Value: ${inputRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}
⚡ Key Points
1. Controlled components → recommended for most cases (clear state management).
2. Uncontrolled components → simple cases, or when working with non-React libraries.
3. Always prevent default form submission with e.preventDefault().
4. Validation can be added easily with controlled components.
❓ Interview-Level Q&A
Q1: What’s the difference between controlled and uncontrolled
components?
Answer:
● Controlled → Input value stored in React state.
● Uncontrolled → Input value stored in DOM, accessed via ref.
Q2: Which is better and why?
Answer:
Controlled components are preferred because they give full control over form data, validation,
and side effects.
Q3: How do you handle multiple form inputs?
Answer:
By using a single state object:
const [form, setForm] = useState({ name: "", email: "" });
<input
name="name"
value={form.name}
onChange={(e) => setForm({ ...form, [e.target.name]: e.target.value
})}
/>
Q4: How do you do form validation in React?
Answer:
● Manual validation with state checks.
● Or use libraries like Formik or React Hook Form.
Q5: Why does React recommend controlled components for forms?
Answer:
Because they keep React state as the single source of truth, making UI predictable and easy
to debug.
🔹 Topic 10: useEffect Hook (Side Effects
in React)
📖 Explanation
React components by default handle rendering UI.
But sometimes, you need to do side effects (things outside the UI).
Examples of side effects:
● Fetching data from an API
● Updating the document title
● Setting up event listeners
● Using timers (setInterval, setTimeout)
👉 That’s where useEffect comes in.
🖥 Example 1: Basic useEffect
import { useEffect, useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
// Side effect: update document title whenever count changes
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // dependency array
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click Me</button>
</div>
);
}
✅ The effect runs every time count changes.
📌 Dependency Array Rules
● useEffect(() => {...}, []) → runs only once (on mount).
● useEffect(() => {...}, [dep]) → runs when dep changes.
● useEffect(() => {...}) → runs on every render (not recommended).
🖥 Example 2: Fetching Data with useEffect
import { useEffect, useState } from "react";
export default function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((data) => setUsers(data));
}, []); // run once on mount
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
🖥 Example 3: Cleanup Function
When you set up subscriptions, event listeners, or timers, you need cleanup.
import { useEffect, useState } from "react";
export default function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((c) => c + 1);
}, 1000);
return () => clearInterval(interval); // cleanup
}, []);
return <p>Timer: {count}</p>;
}
⚡ Key Points
1. useEffect is used for side effects (not pure rendering).
2. Always manage cleanup to avoid memory leaks.
3. Dependency array controls when the effect runs.
4. Common use cases in Next.js:
○ API calls
○ Client-side auth check
○ Analytics/tracking setup
❓ Interview-Level Q&A
Q1: What is the purpose of useEffect?
Answer:
To perform side effects (like data fetching, subscriptions, DOM updates) in functional
components.
Q2: Difference between componentDidMount, componentDidUpdate, and
componentWillUnmount vs useEffect?
Answer:
● In class components:
○ componentDidMount → after mount
○ componentDidUpdate → after update
○ componentWillUnmount → before unmount
● In functional components:
○ useEffect(() => {...}, []) → mount
○ useEffect(() => {...}, [dep]) → update
○ return () => {...} inside useEffect → unmount
Q3: What happens if you don’t pass a dependency array to useEffect?
Answer:
The effect runs after every render, which may cause performance issues or infinite loops.
Q4: Can you make useEffect async?
Answer:
No, but you can define an async function inside it and call it:
useEffect(() => {
async function fetchData() {
const res = await fetch("/api/data");
const data = await res.json();
console.log(data);
}
fetchData();
}, []);
Q5: Why is cleanup important in useEffect?
Answer:
Without cleanup, event listeners, intervals, or subscriptions remain active → causes memory
leaks or unwanted behavior.