React Interview Questions and Answers
Master React interviews with questions on hooks, components, state management, performance optimization, and React 18 features.
š Jump to Question
1. What is React and why should we use it?
React is a JavaScript library created by Facebook for building interactive user interfaces. Think of it like a smart way to build websites where only the parts that need to change actually update, without refreshing the whole page.
Why use React?
- Component-based: Build your UI like LEGO blocks that you can reuse anywhere
- Fast updates: Only updates what changed, not the whole page
- Great for teams: Clear structure makes it easier to work together
- Huge community: Lots of help available and many companies use it
- Works everywhere: Can make websites, mobile apps (React Native), and desktop apps
// A basic React component
function WelcomeMessage() {
return <h1>Hello, welcome to our website!</h1>;
}
2. What is the Virtual DOM?
Imagine you're painting a picture and want to change just one small part. Instead of repainting everything, you only paint over that small area. That's what React does with Virtual DOM.
How it works:
- React keeps a copy of your page in memory (Virtual DOM)
- When something changes, React creates a new Virtual DOM
- React compares the old and new versions (like "spot the difference")
- Only the changed parts update on the actual webpage
- This makes websites much faster
React's Virtual DOM is a JavaScript object that represents what your page looks like. When state changes, React creates a new object, compares it with the old one using a "diffing algorithm," and then efficiently updates only what changed in the real browser DOM.
3. What are Components?
Components are like building blocks for your website. Each component is a self-contained piece of UI with its own logic and appearance.
Types of components:
- Functional Components: Simple functions that return what to display
- Class Components: More feature-rich, use classes (older style)
- Presentational Components: Just show things (like a button)
- Container Components: Handle data and logic
Think of it like this: Your website = House Each room = Component (Kitchen, Bedroom, Living Room) Each component handles its own stuff
// A simple component
function UserProfile(props) {
return (
<div>
<h2>{props.name}</h2>
<p>{props.bio}</p>
</div>
);
}
4. What is JSX?
JSX looks like HTML but it's actually JavaScript. It's React's special language for describing what components should look like.
Key things about JSX:
- Looks like HTML but works inside JavaScript
- Must have a single parent element (wrap multiple elements in a div or fragment)
- Use
classNameinstead ofclass(because "class" is a JavaScript keyword) - Can embed JavaScript expressions with
{}
Simple example: <h1>Hello {userName}</h1> mixes HTML-like tags with JavaScript variables.
// Correct JSX
return (
<div>
<h1>Title</h1>
<p>Content</p>
</div>
);
// Wrong JSX (multiple root elements)
return (
<h1>Title</h1>
<p>Content</p> // Error!
);
5. What are Props?
Props (short for properties) are how you pass data from a parent component to a child component. They're read-only - the child can't change them.
Analogy: Props are like parameters you give to a function. If you have a Greeting component, you might pass it a name prop: <Greeting name="Sarah" />
Important:
- Props flow down (parent ā child)
- Props are immutable (can't be changed by child)
- Use props to make components reusable
// Parent component
function App() {
return <WelcomeMessage name="Alex" />;
}
// Child component receiving props
function WelcomeMessage(props) {
return <h1>Hello, {props.name}!</h1>;
}
State and Lifecycle
6. What is State?
State is data that can change over time within a component. Unlike props (which come from outside), state is managed internally by the component.
Think of state as:
- A component's memory
- Data that changes and causes re-renders
- Local to the component (unless shared)
Example use cases:
- Form input values
- Toggle switches (on/off)
- Counter values
- Loading status (loading/loaded)
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
7. Props vs State - What's the difference?
This is a very common interview question!
Props (Properties):
- Come from parent component
- Are read-only (child can't modify)
- Like function parameters
- Used to pass data down
State:
- Managed within component
- Can be modified using setState
- Like component's memory
- Changes cause re-render
Analogy: If a component is a restaurant table:
- Props = The menu you're given (can't change it)
- State = What you've ordered so far (can add/remove)
| | Props | State | |---|---|---| | Source | Parent component | Component itself | | Can change? | No (immutable) | Yes (mutable) | | Purpose | Pass data down | Track changes | | Changes cause re-render? | Yes (if parent changes) | Yes |
8. What are React Lifecycle Methods?
Lifecycle methods are like different stages in a component's life: birth, updates, and death. They let you run code at specific times.
Main lifecycle stages:
- Mounting - Component is being created and inserted into DOM
- Updating - Component is re-rendering due to props/state changes
- Unmounting - Component is being removed from DOM
Common lifecycle methods:
componentDidMount()- Runs after component appears on screen (good for API calls)componentDidUpdate()- Runs after component updatescomponentWillUnmount()- Runs before component disappears (cleanup)
1. constructor() - Component is being created
2. render() - Component draws itself
3. componentDidMount() - Component is now on screen
4. componentDidUpdate() - Component updated
5. componentWillUnmount() - Component about to disappear
React Hooks (Modern React)
9. What are React Hooks?
Hooks are functions that let you "hook into" React features from functional components. Before hooks, you needed class components for state and lifecycle.
Why hooks were introduced:
- Simplify complex components
- Reuse stateful logic between components
- Make code easier to understand and test
- Reduce the need for class components
Most important hooks:
useState- Add state to functional componentsuseEffect- Handle side effects (API calls, subscriptions)useContext- Access context without nestinguseRef- Reference DOM elements or persistent values
import { useState, useEffect } from 'react';
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
// Fetch user data when component mounts
fetchUser().then(data => setUser(data));
}, []);
if (!user) return <div>Loading...</div>;
return <div>Hello, {user.name}</div>;
}
10. Explain useState Hook
useState is the hook that lets you add state to functional components.
How it works:
- Call
useState(initialValue)- returns [currentValue, setterFunction] - Use the setter function to update state
- Component re-renders with new state
Simple analogy:
useState is like having a variable that, when changed, automatically updates your UI.
function ToggleSwitch() {
const [isOn, setIsOn] = useState(false);
return (
<div>
<p>Switch is {isOn ? 'ON' : 'OFF'}</p>
<button onClick={() => setIsOn(!isOn)}>
Toggle
</button>
</div>
);
}
11. Explain useEffect Hook
useEffect handles side effects - things that happen as a "side effect" of rendering.
What are side effects?
- Fetching data from API
- Setting up subscriptions
- Manually changing the DOM
- Setting timers
How useEffect works:
- Runs after component renders
- Can run once, or when dependencies change
- Can return cleanup function
// Run once (on mount)
useEffect(() => {
console.log('Component mounted');
}, []);
// Run when count changes
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
// With cleanup
useEffect(() => {
const timer = setInterval(() => {
console.log('Tick');
}, 1000);
return () => clearInterval(timer); // Cleanup
}, []);
12. What is the Dependency Array in useEffect?
The dependency array (second argument to useEffect) tells React when to run your effect.
Three patterns:
- No array - Runs after every render (usually avoid this)
- Empty array
[]- Runs once after initial render (likecomponentDidMount) - Array with values
[dep1, dep2]- Runs when any dependency changes (likecomponentDidUpdatefor those values)
// 1. Run on every render (careful!)
useEffect(() => {
// Runs after every render
});
// 2. Run once on mount
useEffect(() => {
// Fetch initial data
}, []);
// 3. Run when userId changes
useEffect(() => {
// Fetch user data
}, [userId]);
13. Explain useContext Hook
useContext lets you access data from React Context without passing props through every level (prop drilling).
Problem it solves: When you need to pass data deep down through many components.
How it works:
- Create a Context
- Wrap components with Provider
- Use
useContextto access the value anywhere below
// Create context
const ThemeContext = React.createContext('light');
// Provide value
function App() {
return (
<ThemeContext.Provider value="dark">
<Header />
</ThemeContext.Provider>
);
}
// Use value
function Header() {
const theme = useContext(ThemeContext);
return <header className={theme}>Header</header>;
}
14. What are useMemo and useCallback?
These hooks optimize performance by memoizing (caching) values and functions.
useMemo - Memoizes expensive calculations useCallback - Memoizes functions so they don't get recreated
When to use them:
- When you have expensive calculations
- When passing callbacks to optimized child components
- To prevent unnecessary re-renders
// Without optimization - re-calculates on every render
const sortedList = list.sort((a, b) => a - b);
// With useMemo - only re-calculates when list changes
const sortedList = useMemo(() => {
return list.sort((a, b) => a - b);
}, [list]);
Component Communication
15. How do components communicate with each other?
Components talk to each other in several ways:
- Parent to Child - Using props
- Child to Parent - Using callback functions passed as props
- Sibling to Sibling - Through common parent (lifting state up)
- Any to Any - Using Context API or state management (Redux)
Lifting State Up: When siblings need to share data, move the state to their closest common ancestor.
// Child to parent communication
function Parent() {
const handleChildEvent = (data) => {
console.log('Child sent:', data);
};
return <Child onEvent={handleChildEvent} />;
}
function Child({ onEvent }) {
return <button onClick={() => onEvent('Hello')}>Send</button>;
}
16. What is Prop Drilling?
Prop drilling happens when you pass props through multiple levels of components just to get them to a deeply nested child.
Problem: Middle components don't use the props, they just pass them along.
Solutions:
- Context API - Share data without passing props
- Component Composition - Pass components as children
- State Management - Redux, Zustand, etc.
// Bad: Prop drilling
<App user={user}> // Uses user
<Header user={user}> // Doesn't use user, just passes
<Navbar user={user}> // Doesn't use user, just passes
<Profile user={user}> // Finally uses user!
</Profile>
</Navbar>
</Header>
</App>
Performance Optimization
17. How to optimize React performance?
React is fast by default, but here are ways to make it faster:
- React.memo() - Memoize components to prevent unnecessary re-renders
- useMemo/useCallback - Memoize values and functions
- Code Splitting - Load code only when needed
- Virtualize Long Lists - Only render visible items
- Avoid Inline Functions - In render methods
- Production Build - Use minified version for deployment
Golden Rule: Don't optimize prematurely. Measure first, then optimize bottlenecks.
// Memoize component
const ExpensiveComponent = React.memo(function MyComponent(props) {
// Only re-renders if props change
return <div>{props.value}</div>;
});
// Code splitting
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
18. What is React.memo?
React.memo is a higher-order component that memoizes your component. If the props haven't changed, it won't re-render.
When to use it:
- Component renders often with same props
- Component is expensive to render
- Props don't change frequently
When NOT to use it:
- Component always gets new props
- Component is cheap to render
- You need latest props always
// Without memo - re-renders on parent re-render
function UserProfile({ user }) {
return <div>{user.name}</div>;
}
// With memo - only re-renders if user prop changes
const UserProfile = React.memo(function({ user }) {
return <div>{user.name}</div>;
});
Advanced Concepts
19. What are Error Boundaries?
Error boundaries are React components that catch JavaScript errors anywhere in their child component tree and display a fallback UI instead of crashing.
What they catch:
- Errors during rendering
- Errors in lifecycle methods
- Errors in constructors
What they DON'T catch:
- Errors in event handlers (use try-catch)
- Errors in asynchronous code
- Errors in server-side rendering
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// Usage
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
20. What are Higher-Order Components (HOC)?
HOC is a pattern where a function takes a component and returns a new component with additional functionality.
Think of it as: Wrapping a gift. The gift (component) stays the same, but you add wrapping paper (extra features).
Common uses:
- Adding authentication checks
- Adding loading states
- Adding data fetching
- Adding styling/theming
function withLoading(WrappedComponent) {
return function EnhancedComponent(props) {
if (props.isLoading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...props} />;
};
}
const UserProfileWithLoading = withLoading(UserProfile);
21. What are Custom Hooks?
Custom hooks let you extract component logic into reusable functions. They're like your own personal hooks!
Rules for custom hooks:
- Name must start with "use" (so React knows it's a hook)
- Can call other hooks
- Should be pure functions
When to create custom hooks:
- When you use the same logic in multiple components
- When component logic gets complex
- To make code more readable
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const stored = localStorage.getItem(key);
return stored ? JSON.parse(stored) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Usage in component
function Component() {
const [name, setName] = useLocalStorage('name', 'Guest');
return <input value={name} onChange={e => setName(e.target.value)} />;
}
State Management
22. When to use Context API vs Redux?
Context API (built into React):
- Good for simple global state (theme, auth, language)
- Less boilerplate
- No middleware
- Good for small to medium apps
Redux (external library):
- Good for complex state with lots of updates
- Time-travel debugging
- Middleware support (thunk, saga)
- Good for large apps with complex state
- More boilerplate but more features
Rule of thumb: Start with Context API, move to Redux if you need its features.
| | Context API | Redux | |---|---|---| | Built-in | Yes | No (external) | | Learning curve | Easy | Steeper | | Boilerplate | Minimal | More | | DevTools | Basic | Excellent | | Middleware | No | Yes | | Performance | Good for small data | Optimized for large |
23. What is Redux?
Redux is a state management library that follows three principles:
- Single Source of Truth - Entire app state in one store
- State is Read-Only - Only changed by dispatching actions
- Changes with Pure Functions - Reducers specify how state changes
Redux Flow:
- Dispatch an action (like sending a message)
- Reducer processes the action (like a rules engine)
- Store updates with new state
- Components re-render with new state
Component ā Action ā Reducer ā Store ā Component
ā ā ā ā ā
Button "ADD_TODO" Updates New state Renders
Click state saved with new
data
React Router
24. What is React Router?
React Router is the standard library for adding navigation to React apps. It lets you create single-page applications with multiple "pages" without reloading.
Key concepts:
- Routes - Map URLs to components
- Links - Navigation between routes
- Params - Dynamic parts of URLs (like
/users/:id) - Nested Routes - Routes inside routes
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:id" element={<UserProfile />} />
</Routes>
</BrowserRouter>
);
}
Testing
25. How to test React components?
Testing ensures your components work correctly. Common approaches:
- Unit Tests - Test individual components/functions
- Integration Tests - Test how components work together
- End-to-End Tests - Test complete user flows
Popular tools:
- Jest - Testing framework (created by Facebook)
- React Testing Library - Test components like users do
- Cypress - End-to-end testing
// Test a button component
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
test('button shows correct text', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
test('button click works', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click</Button>);
fireEvent.click(screen.getByText('Click'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
React 18 Features
26. What's new in React 18?
React 18 focuses on improving performance and user experience:
- Concurrent Features - React can work on multiple tasks at once
- Automatic Batching - Multiple state updates grouped together
- Transitions - Mark some updates as non-urgent
- Suspense for Data Fetching - Better loading states
- New Root API -
ReactDOM.createRoot()
Concurrent React: Like having multiple checkout lanes instead of one - better experience when many things happen at once.
// React 18 Root API
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
// useTransition hook
const [isPending, startTransition] = useTransition();
startTransition(() => {
// Non-urgent update (won't block UI)
setFilter(newFilter);
});
Common Patterns
27. Controlled vs Uncontrolled Components
Controlled Components:
- Form data handled by React state
- Single source of truth
- React controls the value
- More code, more control
Uncontrolled Components:
- Form data handled by DOM
- Use refs to get values
- Less code, less control
- Good for simple forms
// Controlled
const [value, setValue] = useState('');
<input value={value} onChange={e => setValue(e.target.value)} />
// Uncontrolled
const inputRef = useRef();
<input ref={inputRef} defaultValue="initial" />
// Read value: inputRef.current.value
28. What are React Fragments?
Fragments let you group multiple children without adding an extra DOM element.
Why use them:
- Avoid unnecessary div wrappers
- Cleaner HTML output
- Better for CSS (no extra container)
- Required when returning multiple elements
// Long form
return (
<React.Fragment>
<ChildA />
<ChildB />
</React.Fragment>
);
// Short form (most common)
return (
<>
<ChildA />
<ChildB />
</>
);
29. What are React Portals?
Portals let you render children into a DOM node that exists outside the parent component's hierarchy.
Use cases:
- Modals
- Tooltips
- Popovers
- Dialogs
Why portals: Keeps the React component structure clean while rendering elsewhere in DOM.
// Modal renders at end of body, not inside parent
function Modal({ children }) {
return ReactDOM.createPortal(
children,
document.getElementById('modal-root')
);
}
// In HTML: <div id="modal-root"></div>
Best Practices
30. React Best Practices for 2026
- Use Functional Components - With hooks, classes are rarely needed
- Keep Components Small - One component, one responsibility
- Use TypeScript - Catches errors early, better documentation
- Follow Naming Conventions - PascalCase for components, camelCase for functions
- Destructure Props - Makes code cleaner:
function User({ name, age }) - Use Fragment Over Div - When you don't need styling
- Memoize Wisely - Only when you measure performance issues
- Handle Loading & Error States - Better user experience
- Use Environment Variables - Don't hardcode API URLs
- Write Tests - Especially for complex logic
src/
āāā components/ # Reusable components
āāā features/ # Feature-specific components
āāā hooks/ # Custom hooks
āāā utils/ # Helper functions
āāā services/ # API calls
āāā store/ # State management
āāā pages/ # Page components
Interview Coding Questions
31. Create a Counter Component
Build a counter with increment, decrement, and reset buttons.
Requirements:
- Display current count
- Buttons to increment/decrement
- Reset to zero
- Don't go below zero
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count > 0 ? count - 1 : 0);
const reset = () => setCount(0);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
</div>
);
}
32. Fetch and Display Data
Fetch users from an API and display them in a list.
Requirements:
- Show loading state
- Handle errors
- Display user name and email
- Retry on failure
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => {
if (!response.ok) throw new Error('Failed to fetch');
return response.json();
})
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(err => {
setError(err.message);
setLoading(false);
});
}, []);
if (loading) return <div>Loading users...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>
<strong>{user.name}</strong> - {user.email}
</li>
))}
</ul>
);
}
33. Todo List Application
Build a todo list with add, complete, and delete functionality.
Requirements:
- Add new todos
- Mark todos as complete
- Delete todos
- Show completed count
- Filter (all/active/completed)
function TodoApp() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
if (input.trim()) {
setTodos([...todos, {
id: Date.now(),
text: input,
completed: false
}]);
setInput('');
}
};
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
const completedCount = todos.filter(t => t.completed).length;
return (
<div>
<h2>Todos ({completedCount}/{todos.length})</h2>
<div>
<input
value={input}
onChange={e => setInput(e.target.value)}
placeholder="Add new todo"
onKeyPress={e => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>Add</button>
</div>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span style={{
textDecoration: todo.completed ? 'line-through' : 'none',
color: todo.completed ? '#999' : '#000'
}}>
{todo.text}
</span>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
Quick Reference
Essential Hooks Cheatsheet
useState- Add state to functional componentsuseEffect- Handle side effects (API, subscriptions)useContext- Access context without prop drillinguseRef- Reference DOM elements or keep values between rendersuseReducer- Complex state logic (like Redux)useMemo- Memoize expensive calculationsuseCallback- Memoize functions to prevent re-renders
Common Performance Issues & Solutions
- Too many re-renders ā Use React.memo, useMemo, useCallback
- Large bundle size ā Code splitting, dynamic imports
- Slow lists ā Virtualization (react-window)
- Memory leaks ā Cleanup in useEffect return
- Blocking UI ā Use transitions (React 18)
Folder Structure Recommendations
src/
āāā components/ # Shared components (Button, Input, Modal)
ā āāā common/ # Very generic components
ā āāā ui/ # UI-specific components
āāā features/ # Feature-based components
ā āāā auth/ # Login, register components
ā āāā dashboard/ # Dashboard components
ā āāā profile/ # User profile components
āāā hooks/ # Custom hooks
āāā utils/ # Helper functions
āāā services/ # API services
āāā contexts/ # React contexts
āāā store/ # State management (Redux/Zustand)
āāā pages/ # Page components