React Interview Questions: Junior Level (0–2 Years)
50 React interview questions with detailed answers for junior developers — JSX, components, props, state, hooks basics, and lifecycle. Includes what interviewers really want to hear.
How to Use This Guide
For each question, there's a short answer (what to say in the first 15 seconds) and a full answer (what to add if they ask you to elaborate). Interviewers aren't looking for textbook definitions — they're looking for whether you understand why.
JSX & Components
Q1: What is JSX and why does React use it?
Short answer: JSX is a syntax extension that lets you write HTML-like code inside JavaScript. It compiles to React.createElement() calls.
Full answer:
// What you write
const element = <h1 className="title">Hello</h1>;
// What Babel compiles it to
const element = React.createElement("h1", { className: "title" }, "Hello");React uses JSX because it lets you describe UI structure close to the logic that drives it. It's not required — you could use React.createElement directly — but JSX makes component trees readable.
Q2: What is the difference between a functional component and a class component?
Short answer: Functional components are plain functions that return JSX. Class components extend React.Component and use lifecycle methods. For all new code, use functional components with hooks.
Full answer:
// Class component (legacy)
class Welcome extends React.Component {
state = { count: 0 };
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
// Functional component (modern)
function Welcome({ name }) {
const [count, setCount] = useState(0);
return <h1>Hello, {name}</h1>;
}Functional components are shorter, easier to test, and the only way to use hooks. Class components are only needed for error boundaries.
Q3: What rules must you follow when writing JSX?
- Single root element (or use
<>...</>Fragment) classNameinstead ofclass;htmlForinstead offor- Self-close empty elements:
<img />,<br />,<input /> - JavaScript expressions go in
{ }, not{{ }} - Event handlers are camelCase:
onClick,onChange,onSubmit
// Wrong
<div class="box">
<p>Hello</p>
<p>World</p>
</div>
// Right
<>
<p>Hello</p>
<p>World</p>
</>Q4: What is a React Fragment and why would you use it?
Short answer: A Fragment groups elements without adding extra DOM nodes.
// Without Fragment — adds an unwanted <div>
return (
<div>
<dt>Term</dt>
<dd>Definition</dd>
</div>
);
// With Fragment — no extra DOM node
return (
<>
<dt>Term</dt>
<dd>Definition</dd>
</>
);
// Long form — required when you need to pass a key
return items.map((item) => (
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
</React.Fragment>
));Q5: What is the key prop and why is it important in lists?
Short answer: key helps React identify which list items changed, preventing unnecessary re-renders.
Full answer: Without keys, React uses index — inserting an item at position 0 shifts all other items' indexes, causing React to re-render every item. With stable keys (database IDs), React knows exactly what changed.
// Wrong — index as key breaks with reordering or filtering
{items.map((item, index) => <Item key={index} item={item} />)}
// Right — stable ID as key
{items.map((item) => <Item key={item.id} item={item} />)}Props
Q6: What are props?
Props are inputs passed from a parent component to a child. They are read-only — the child cannot modify them.
// Parent passes props
<UserCard name="Alice" role="admin" onDelete={handleDelete} />
// Child receives and uses props
function UserCard({ name, role, onDelete }) {
return (
<div>
<h3>{name}</h3>
<span>{role}</span>
<button onClick={onDelete}>Delete</button>
</div>
);
}Q7: How do you set default prop values?
// Destructuring defaults (preferred with functional components)
function Button({ label = "Click me", variant = "primary", disabled = false }) {
return <button className={variant} disabled={disabled}>{label}</button>;
}Q8: What is the children prop?
children is the content between component opening and closing tags. It lets you build wrapper/layout components.
function Card({ children, title }) {
return (
<div className="card">
<h2>{title}</h2>
<div className="card-body">{children}</div>
</div>
);
}
// Usage
<Card title="Profile">
<Avatar />
<Bio text="Frontend developer" />
</Card>State
Q9: What is state and how is it different from props?
| | Props | State | |---|---|---| | Who controls it | Parent component | The component itself | | Mutable? | No (from child's view) | Yes, via setter | | Re-renders on change? | When parent re-renders | Yes, immediately | | Direction | Top-down | Internal |
Q10: How do you update state correctly?
Always use the setter function. Never mutate state directly.
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: "Alice", age: 30 });
const [items, setItems] = useState(["a", "b", "c"]);
// ❌ Wrong: direct mutation
count = count + 1;
user.name = "Bob";
items.push("d");
// ✅ Right: use setter with new values
setCount(count + 1);
setUser({ ...user, name: "Bob" }); // Spread old, override changed fields
setItems([...items, "d"]); // Spread old, add new
setItems(prev => prev.filter(i => i !== "b")); // Functional update for derived stateQ11: What is the functional form of setState and when do you use it?
When the new state depends on the previous state, use the functional form to avoid stale closures:
// ❌ Can give wrong result if called multiple times in a row
setCount(count + 1);
setCount(count + 1); // Still increments by 1 total
// ✅ Always gets the latest value
setCount(prev => prev + 1);
setCount(prev => prev + 1); // Increments by 2 totalQ12: What happens when you call setState with the same value as the current state?
React bails out and skips the re-render. For objects and arrays, it uses reference equality (===). This is why mutating an array directly and calling setState with the same reference won't trigger a re-render.
Hooks Basics
Q13: What are React hooks?
Hooks are functions that let functional components use React features like state, lifecycle, and context. They must be called at the top level of a component — not inside loops, conditions, or nested functions.
Rules:
- Only call hooks at the top level
- Only call hooks from React functions (components or other hooks)
Q14: When does useEffect run?
useEffect(() => { /* ... */ }); // After every render
useEffect(() => { /* ... */ }, []); // Once after mount
useEffect(() => { /* ... */ }, [userId]); // After mount + when userId changesThe cleanup function (the returned function) runs before the next effect or on unmount:
useEffect(() => {
const subscription = api.subscribe(userId, handleUpdate);
return () => subscription.unsubscribe(); // Cleanup
}, [userId]);Q15: What is the purpose of useRef?
useRef gives you a mutable container that persists across renders without causing re-renders when changed. Two main uses:
// 1. Access a DOM element
const inputRef = useRef(null);
useEffect(() => { inputRef.current.focus(); }, []);
return <input ref={inputRef} />;
// 2. Store a value without triggering re-renders
const renderCount = useRef(0);
useEffect(() => { renderCount.current++; }); // No re-renderConditional Rendering
Q16: What are the different ways to conditionally render in React?
function Notifications({ count, isLoggedIn, message }) {
// 1. Early return
if (!isLoggedIn) return null;
// 2. Ternary
const status = count > 0 ? <Badge count={count} /> : <p>No notifications</p>;
// 3. Logical AND (watch the 0 trap!)
// BAD: count && <X /> renders "0" when count is 0
// GOOD:
const badge = count > 0 && <Badge count={count} />;
// 4. Object lookup
const icons = { success: <CheckIcon />, error: <XIcon />, info: <InfoIcon /> };
return <div>{status}{badge}{icons[message.type]}</div>;
}Q17: How do you handle events in React?
function Form() {
const handleSubmit = (e) => {
e.preventDefault(); // Prevent default browser behavior
const data = new FormData(e.target);
console.log(Object.fromEntries(data));
};
const handleChange = (e) => {
console.log(e.target.value);
};
// Pass function reference — don't call it: onClick={handleClick}, NOT onClick={handleClick()}
return (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} />
<button type="submit">Submit</button>
</form>
);
}Common Interview Traps
Q18: Why can't you update state directly?
React uses reference equality to detect changes. If you mutate an object in place, the reference stays the same — React sees no change and skips the re-render. Always return a new object/array.
Q19: What is the difference between undefined and null in JSX?
Both undefined, null, false, and true render nothing (no DOM output). However, 0 DOES render as text. This is the common bug with count && <X />.
Q20: Can you call hooks inside a conditional?
No. Hooks must always be called in the same order every render. React tracks hooks by order of calls. If you call a hook inside an if, the order can change between renders, breaking React's internal tracking.
// ❌ Wrong
if (isLoggedIn) {
const [data, setData] = useState(null); // Hook inside condition
}
// ✅ Right: call hook always, use result conditionally
const [data, setData] = useState(null);
if (!isLoggedIn) return null;What Junior Interviewers Actually Look For
-
Can you explain the why? Not just "state causes re-renders" but "because React needs to know what changed to update the UI efficiently."
-
Do you know common mistakes? Direct state mutation, wrong key usage, forgetting cleanup in useEffect.
-
Can you read and reason about code? Given a component, can you explain what it does step by step?
-
Are you comfortable building small features? Even if you stumble on a question, showing you can implement something is more valuable.
Common junior mistakes to avoid:
- Saying "useEffect is componentDidMount" — it's not exactly. It's about synchronization.
- Confusing controlled and uncontrolled inputs.
- Not knowing what the
keyprop is for. - Mutating state directly.
Enjoyed this article?
Explore the Frontend Engineering learning path for more.
Found this helpful?
Leave a comment
Have a question, correction, or just found this helpful? Leave a note below.