React JS Interview Questions 2025: Complete Guide with Latest Trends and Expert Answers
Table of Contents
- Introduction: React JS Interview Landscape in 2025
- Essential React JS Fundamentals
- React Hooks Interview Questions
- React 18 & Latest Features
- Advanced React Concepts
- Performance Optimization Questions
- State Management & Context API
- Testing & Best Practices
- Common Coding Challenges
- Tips for React JS Interview Success
Introduction: React JS Interview Landscape in 2025 {#introduction}
React.js continues to dominate the frontend development landscape in 2025, with major companies like Facebook, PayPal, Instagram, and Uber heavily investing in React-based solutions. The interview landscape has evolved significantly, with employers now focusing on React 18 features, Server Components, concurrent rendering, and advanced hooks patterns.
This comprehensive guide covers the most frequently asked React JS interview questions, from fundamental concepts to cutting-edge features that are trending in 2025. Whether you're a fresher or an experienced developer, this resource will help you ace your next React interview.
Why React JS Remains In-Demand in 2025
- Component-based architecture enables reusable and maintainable code
- Virtual DOM provides exceptional performance optimization
- Rich ecosystem with extensive library support
- Strong community and continuous innovation
- Cross-platform development capabilities with React Native
Essential React JS Fundamentals {#fundamentals}
1. What is React JS and why is it popular?
Answer: React is an open-source JavaScript library developed by Facebook for building user interfaces, particularly single-page applications. It's popular because:
- Component-based architecture promotes code reusability
- Virtual DOM ensures efficient rendering and performance
- Unidirectional data flow makes applications predictable
- JSX syntax provides intuitive template writing
- Strong ecosystem with extensive tooling and libraries
2. Explain the Virtual DOM and its benefits
Answer: The Virtual DOM is a lightweight JavaScript representation of the actual DOM. React uses it to:
- Minimize direct DOM manipulation which is expensive
- Batch updates for better performance
- Enable diffing algorithm to identify changes efficiently
- Provide cross-browser compatibility
- Enable server-side rendering capabilities
3. What is JSX and why do we use it?
Answer: JSX (JavaScript XML) is a syntax extension that allows writing HTML-like code within JavaScript. Benefits include:
- Improved readability with familiar HTML-like syntax
- Type safety with compile-time error checking
- Component composition becomes more intuitive
- Performance optimization through Babel transpilation
// JSX Example
const Welcome = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
4. Difference between Functional and Class Components
Answer:
Functional Components:
- Simpler syntax and easier to test
- Can use hooks for state and lifecycle methods
- Better performance with React's optimizations
- Preferred approach in modern React development
Class Components:
- Traditional OOP approach
- Built-in lifecycle methods
- More verbose syntax
- Still supported but less commonly used
// Functional Component
const Counter = () => {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
};
// Class Component
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
{this.state.count}
</button>
);
}
}
React Hooks Interview Questions {#hooks}
5. What are React Hooks and their advantages?
Answer: React Hooks are functions that allow you to use state and lifecycle features in functional components. Advantages include:
- Reusable stateful logic between components
- Simplified component structure without class complexity
- Better code organization with custom hooks
- Improved testing capabilities
- Enhanced performance with optimized re-renders
6. Explain useState Hook with examples
Answer: useState is a hook that adds state management to functional components.
import React, { useState } from "react";
const UserProfile = () => {
const [user, setUser] = useState({ name: "", email: "" });
const [loading, setLoading] = useState(false);
const updateUser = (field, value) => {
setUser((prevUser) => ({ ...prevUser, [field]: value }));
};
return (
<div>
<input
value={user.name}
onChange={(e) => updateUser("name", e.target.value)}
placeholder="Name"
/>
<input
value={user.email}
onChange={(e) => updateUser("email", e.target.value)}
placeholder="Email"
/>
{loading && <p>Loading...</p>}
</div>
);
};
7. What is useEffect and its use cases?
Answer: useEffect manages side effects in functional components, replacing lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.
import React, { useState, useEffect } from "react";
const DataFetcher = ({ userId }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
// Effect for data fetching
useEffect(() => {
const fetchUser = async () => {
setLoading(true);
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
} catch (error) {
console.error("Failed to fetch user:", error);
} finally {
setLoading(false);
}
};
if (userId) {
fetchUser();
}
// Cleanup function
return () => {
// Cancel any pending requests
};
}, [userId]); // Dependency array
if (loading) return <div>Loading...</div>;
return <div>{user?.name}</div>;
};
8. Explain useContext Hook and when to use it
Answer: useContext allows components to consume context values without nesting Context.Consumer components.
import React, { createContext, useContext, useState } from "react";
// Create context
const ThemeContext = createContext();
// Provider component
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// Consumer component
const ThemeToggle = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<button onClick={toggleTheme} className={`btn ${theme}`}>
Switch to {theme === "light" ? "dark" : "light"} mode
</button>
);
};
React 18 & Latest Features {#react-18}
9. What are the key features of React 18?
Answer: React 18 introduced several groundbreaking features:
Concurrent Rendering:
- Enables React to pause, resume, and prioritize work
- Improves user experience with better responsiveness
- Allows for time-slicing and prioritization
Automatic Batching:
- Groups multiple state updates into a single re-render
- Works with promises, timeouts, and native event handlers
- Improves performance significantly
Suspense Improvements:
- Better support for data fetching
- Enhanced server-side rendering capabilities
- Improved error boundaries integration
// Concurrent Features Example
import { startTransition, useDeferredValue } from "react";
const SearchResults = ({ query }) => {
const [results, setResults] = useState([]);
const deferredQuery = useDeferredValue(query);
const handleSearch = (newQuery) => {
startTransition(() => {
// This update is marked as non-urgent
performSearch(newQuery).then(setResults);
});
};
return (
<div>
<input onChange={(e) => handleSearch(e.target.value)} />
<Results query={deferredQuery} results={results} />
</div>
);
};
10. Explain React Server Components
Answer: React Server Components run on the server and render to a special format that can be streamed to the client. Benefits include:
- Zero bundle size impact for server components
- Direct database access without API layers
- Improved performance with server-side rendering
- Better SEO capabilities
// Server Component Example
async function ProductList() {
// This runs on the server
const products = await db.products.findMany();
return (
<div>
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
// Client Component
("use client");
function ProductCard({ product }) {
const [liked, setLiked] = useState(false);
return (
<div>
<h3>{product.name}</h3>
<button onClick={() => setLiked(!liked)}>{liked ? "❤️" : "🤍"}</button>
</div>
);
}
11. What are the new hooks in React 18?
Answer: React 18 introduced several new hooks:
useId:
const MyComponent = () => {
const id = useId();
return (
<div>
<label htmlFor={id}>Username:</label>
<input id={id} type="text" />
</div>
);
};
useDeferredValue:
const SearchResults = ({ query }) => {
const deferredQuery = useDeferredValue(query);
const results = useMemo(() => searchData(deferredQuery), [deferredQuery]);
return <ResultsList results={results} />;
};
useTransition:
const TabContainer = () => {
const [isPending, startTransition] = useTransition();
const [tab, setTab] = useState("home");
const selectTab = (nextTab) => {
startTransition(() => {
setTab(nextTab);
});
};
return (
<div>
{isPending && <Spinner />}
<TabButton onClick={() => selectTab("home")}>Home</TabButton>
<TabButton onClick={() => selectTab("posts")}>Posts</TabButton>
</div>
);
};
Advanced React Concepts {#advanced}
12. Explain Higher-Order Components (HOCs)
Answer: HOCs are functions that take a component and return a new component with additional functionality.
// HOC for authentication
const withAuth = (WrappedComponent) => {
return (props) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
checkAuthStatus().then((status) => {
setIsAuthenticated(status);
setLoading(false);
});
}, []);
if (loading) return <LoadingSpinner />;
if (!isAuthenticated) return <LoginForm />;
return <WrappedComponent {...props} />;
};
};
// Usage
const ProtectedDashboard = withAuth(Dashboard);
13. What are Render Props and their use cases?
Answer: Render Props is a pattern where a component accepts a function as a prop to determine what to render.
const DataFetcher = ({ url, render }) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [url]);
return render({ data, loading, error });
};
// Usage
const UserProfile = ({ userId }) => (
<DataFetcher
url={`/api/users/${userId}`}
render={({ data, loading, error }) => {
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
return <UserCard user={data} />;
}}
/>
);
14. Explain React Error Boundaries
Answer: Error Boundaries are React components that catch JavaScript errors in their component tree and display fallback UI.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
// Log error to monitoring service
console.error("Error caught by boundary:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="error-boundary">
<h2>Something went wrong.</h2>
<details>{this.state.error && this.state.error.toString()}</details>
</div>
);
}
return this.props.children;
}
}
// Usage
const App = () => (
<ErrorBoundary>
<Header />
<MainContent />
<Footer />
</ErrorBoundary>
);
Performance Optimization Questions {#performance}
15. How do you optimize React application performance?
Answer: Several strategies can optimize React performance:
React.memo for component memoization:
const ExpensiveComponent = React.memo(
({ data, onUpdate }) => {
return (
<div>
{data.map((item) => (
<Item key={item.id} item={item} />
))}
</div>
);
},
(prevProps, nextProps) => {
// Custom comparison function
return prevProps.data.length === nextProps.data.length;
}
);
useCallback for function memoization:
const TodoList = ({ todos, onToggle }) => {
const handleToggle = useCallback(
(id) => {
onToggle(id);
},
[onToggle]
);
return (
<div>
{todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} onToggle={handleToggle} />
))}
</div>
);
};
useMemo for expensive calculations:
const DataVisualization = ({ rawData, filterCriteria }) => {
const processedData = useMemo(() => {
return rawData
.filter(filterCriteria)
.map((item) => expensiveTransformation(item))
.sort((a, b) => a.priority - b.priority);
}, [rawData, filterCriteria]);
return <Chart data={processedData} />;
};
16. Explain code splitting and lazy loading in React
Answer: Code splitting helps reduce bundle size by loading components only when needed.
import React, { Suspense, lazy } from "react";
// Lazy load components
const Dashboard = lazy(() => import("./Dashboard"));
const Profile = lazy(() => import("./Profile"));
const Settings = lazy(() => import("./Settings"));
const App = () => {
const [currentView, setCurrentView] = useState("dashboard");
const renderView = () => {
switch (currentView) {
case "dashboard":
return <Dashboard />;
case "profile":
return <Profile />;
case "settings":
return <Settings />;
default:
return <Dashboard />;
}
};
return (
<div>
<Navigation onViewChange={setCurrentView} />
<Suspense fallback={<LoadingSpinner />}>{renderView()}</Suspense>
</div>
);
};
17. What is React.StrictMode and its benefits?
Answer: React.StrictMode is a tool for highlighting potential problems in applications during development.
const App = () => (
<React.StrictMode>
<Header />
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
<Footer />
</React.StrictMode>
);
Benefits include:
- Identifying unsafe lifecycles
- Warning about legacy string ref API usage
- Warning about deprecated findDOMNode usage
- Detecting unexpected side effects
- Warning about legacy context API
State Management & Context API {#state-management}
18. How do you manage complex state in React applications?
Answer: Several approaches exist for complex state management:
useReducer for complex state logic:
const initialState = {
user: null,
posts: [],
loading: false,
error: null,
};
const appReducer = (state, action) => {
switch (action.type) {
case "FETCH_START":
return { ...state, loading: true, error: null };
case "FETCH_USER_SUCCESS":
return { ...state, user: action.payload, loading: false };
case "FETCH_POSTS_SUCCESS":
return { ...state, posts: action.payload, loading: false };
case "FETCH_ERROR":
return { ...state, error: action.payload, loading: false };
default:
return state;
}
};
const App = () => {
const [state, dispatch] = useReducer(appReducer, initialState);
const fetchUser = async (userId) => {
dispatch({ type: "FETCH_START" });
try {
const user = await api.getUser(userId);
dispatch({ type: "FETCH_USER_SUCCESS", payload: user });
} catch (error) {
dispatch({ type: "FETCH_ERROR", payload: error.message });
}
};
return (
<AppContext.Provider value={{ state, dispatch, fetchUser }}>
<MainApp />
</AppContext.Provider>
);
};
19. When would you use Redux vs Context API?
Answer:
Use Context API when:
- Application has simple to moderate state complexity
- State changes are infrequent
- Component tree is not deeply nested
- You want to avoid external dependencies
Use Redux when:
- Complex state management requirements
- Need time-travel debugging
- Frequent state updates across many components
- Need middleware for async operations
- Large team collaboration requires predictable state updates
// Context API Example
const UserContext = createContext();
const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [preferences, setPreferences] = useState({});
const login = async (credentials) => {
const userData = await authService.login(credentials);
setUser(userData);
};
const logout = () => {
setUser(null);
setPreferences({});
};
return (
<UserContext.Provider
value={{
user,
preferences,
login,
logout,
setPreferences,
}}
>
{children}
</UserContext.Provider>
);
};
Testing & Best Practices {#testing}
20. How do you test React components?
Answer: React components can be tested using various approaches:
Unit Testing with React Testing Library:
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import Counter from "./Counter";
describe("Counter Component", () => {
test("renders initial count", () => {
render(<Counter initialCount={0} />);
expect(screen.getByText("Count: 0")).toBeInTheDocument();
});
test("increments count on button click", async () => {
const user = userEvent.setup();
render(<Counter initialCount={0} />);
const incrementButton = screen.getByRole("button", { name: /increment/i });
await user.click(incrementButton);
expect(screen.getByText("Count: 1")).toBeInTheDocument();
});
test("calls onCountChange when count updates", async () => {
const mockOnCountChange = jest.fn();
const user = userEvent.setup();
render(<Counter initialCount={0} onCountChange={mockOnCountChange} />);
const incrementButton = screen.getByRole("button", { name: /increment/i });
await user.click(incrementButton);
expect(mockOnCountChange).toHaveBeenCalledWith(1);
});
});
Testing Hooks:
import { renderHook, act } from "@testing-library/react";
import useCounter from "./useCounter";
describe("useCounter hook", () => {
test("should initialize with default value", () => {
const { result } = renderHook(() => useCounter());
expect(result.current.count).toBe(0);
});
test("should increment count", () => {
const { result } = renderHook(() => useCounter(0));
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
});
21. What are React development best practices?
Answer: Key best practices include:
Component Organization:
- Keep components small and focused
- Use functional components with hooks
- Implement proper prop validation
- Follow consistent naming conventions
Performance Optimization:
- Use React.memo judiciously
- Implement proper key props for lists
- Avoid inline object creation in render
- Use callback and memo hooks appropriately
Code Quality:
// Good: Proper component structure
const UserCard = ({ user, onEdit, onDelete }) => {
const handleEdit = useCallback(() => {
onEdit(user.id);
}, [user.id, onEdit]);
const handleDelete = useCallback(() => {
onDelete(user.id);
}, [user.id, onDelete]);
return (
<div className="user-card">
<img src={user.avatar} alt={`${user.name}'s avatar`} />
<h3>{user.name}</h3>
<p>{user.email}</p>
<div className="actions">
<button onClick={handleEdit}>Edit</button>
<button onClick={handleDelete}>Delete</button>
</div>
</div>
);
};
UserCard.propTypes = {
user: PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
email: PropTypes.string.isRequired,
avatar: PropTypes.string,
}).isRequired,
onEdit: PropTypes.func.isRequired,
onDelete: PropTypes.func.isRequired,
};
Common Coding Challenges {#coding-challenges}
22. Build a custom hook for API data fetching
Answer:
import { useState, useEffect, useCallback } from "react";
const useApi = (url, options = {}) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = useCallback(async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, {
headers: {
"Content-Type": "application/json",
...options.headers,
},
...options,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, [url, options]);
useEffect(() => {
fetchData();
}, [fetchData]);
const refetch = useCallback(() => {
fetchData();
}, [fetchData]);
return { data, loading, error, refetch };
};
// Usage
const UserProfile = ({ userId }) => {
const {
data: user,
loading,
error,
refetch,
} = useApi(`/api/users/${userId}`);
if (loading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} onRetry={refetch} />;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
<button onClick={refetch}>Refresh</button>
</div>
);
};
23. Implement a search component with debouncing
Answer:
import { useState, useEffect, useMemo } from "react";
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
};
const SearchComponent = ({ data, searchFields = ["name"] }) => {
const [searchTerm, setSearchTerm] = useState("");
const [isSearching, setIsSearching] = useState(false);
const debouncedSearchTerm = useDebounce(searchTerm, 300);
const filteredResults = useMemo(() => {
if (!debouncedSearchTerm.trim()) return data;
return data.filter((item) =>
searchFields.some((field) =>
item[field]?.toLowerCase().includes(debouncedSearchTerm.toLowerCase())
)
);
}, [data, debouncedSearchTerm, searchFields]);
useEffect(() => {
setIsSearching(searchTerm !== debouncedSearchTerm);
}, [searchTerm, debouncedSearchTerm]);
return (
<div>
<div className="search-container">
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="search-input"
/>
{isSearching && (
<span className="searching-indicator">Searching...</span>
)}
</div>
<div className="results">
{filteredResults.length === 0 ? (
<p>No results found</p>
) : (
filteredResults.map((item) => (
<div key={item.id} className="result-item">
<h3>{item.name}</h3>
<p>{item.description}</p>
</div>
))
)}
</div>
</div>
);
};
24. Create a modal component with portal
Answer:
import { createPortal } from "react-dom";
import { useEffect, useRef } from "react";
const Modal = ({ isOpen, onClose, title, children }) => {
const modalRef = useRef(null);
useEffect(() => {
const handleEscape = (event) => {
if (event.key === "Escape") {
onClose();
}
};
const handleClickOutside = (event) => {
if (modalRef.current && !modalRef.current.contains(event.target)) {
onClose();
}
};
if (isOpen) {
document.addEventListener("keydown", handleEscape);
document.addEventListener("mousedown", handleClickOutside);
document.body.style.overflow = "hidden";
}
return () => {
document.removeEventListener("keydown", handleEscape);
document.removeEventListener("mousedown", handleClickOutside);
document.body.style.overflow = "unset";
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return createPortal(
<div className="modal-overlay">
<div
className="modal-content"
ref={modalRef}
role="dialog"
aria-modal="true"
>
<div className="modal-header">
<h2>{title}</h2>
<button
onClick={onClose}
className="close-button"
aria-label="Close modal"
>
×
</button>
</div>
<div className="modal-body">{children}</div>
</div>
</div>,
document.body
);
};
// Usage
const App = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
<Modal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
title="Confirmation"
>
<p>Are you sure you want to delete this item?</p>
<div className="modal-actions">
<button onClick={() => setIsModalOpen(false)}>Cancel</button>
<button onClick={handleDelete}>Delete</button>
</div>
</Modal>
</div>
);
};
Tips for React JS Interview Success {#tips}
Technical Preparation Strategy
-
Master the Fundamentals
- Understand React's core concepts thoroughly
- Practice component lifecycle and hooks regularly
- Be comfortable with JSX and JavaScript ES6+ features
-
Stay Updated with Latest Features
- Learn React 18 concurrent features
- Understand Server Components concepts
- Practice with new hooks like useId, useDeferredValue
-
Practice Coding Challenges
- Build small applications from scratch
- Implement common patterns like HOCs and render props
- Practice debugging and performance optimization
-
Understand the Ecosystem
- Familiarize yourself with popular libraries (React Router, Redux, etc.)
- Know testing frameworks (Jest, React Testing Library)
- Understand build tools and development workflow
Interview Day Best Practices
-
Communication is Key
- Explain your thought process clearly
- Ask clarifying questions when needed
- Walk through your solution step by step
- Discuss trade-offs and alternative approaches
-
Code Quality Matters
- Write clean, readable code
- Use meaningful variable names
- Add comments for complex logic
- Consider edge cases and error handling
-
Demonstrate Problem-Solving Skills
- Break down complex problems into smaller parts
- Start with a basic solution and iterate
- Show how you would test your code
- Discuss potential improvements
Common Interview Scenarios
Scenario 1: Building a Todo App
const TodoApp = () => {
const [todos, setTodos] = useState([]);
const [filter, setFilter] = useState("all");
const [newTodo, setNewTodo] = useState("");
const addTodo = (text) => {
const todo = {
id: Date.now(),
text: text.trim(),
completed: false,
createdAt: new Date(),
};
setTodos((prev) => [...prev, todo]);
setNewTodo("");
};
const toggleTodo = (id) => {
setTodos((prev) =>
prev.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};
const deleteTodo = (id) => {
setTodos((prev) => prev.filter((todo) => todo.id !== id));
};
const filteredTodos = useMemo(() => {
switch (filter) {
case "active":
return todos.filter((todo) => !todo.completed);
case "completed":
return todos.filter((todo) => todo.completed);
default:
return todos;
}
}, [todos, filter]);
return (
<div className="todo-app">
<h1>Todo Application</h1>
<div className="todo-input">
<input
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
onKeyPress={(e) => e.key === "Enter" && addTodo(newTodo)}
placeholder="Add a new todo..."
/>
<button onClick={() => addTodo(newTodo)}>Add</button>
</div>
<div className="filters">
<button
className={filter === "all" ? "active" : ""}
onClick={() => setFilter("all")}
>
All
</button>
<button
className={filter === "active" ? "active" : ""}
onClick={() => setFilter("active")}
>
Active
</button>
<button
className={filter === "completed" ? "active" : ""}
onClick={() => setFilter("completed")}
>
Completed
</button>
</div>
<div className="todo-list">
{filteredTodos.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={toggleTodo}
onDelete={deleteTodo}
/>
))}
</div>
</div>
);
};
const TodoItem = React.memo(({ todo, onToggle, onDelete }) => (
<div className={`todo-item ${todo.completed ? "completed" : ""}`}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => onDelete(todo.id)}>Delete</button>
</div>
));
Scenario 2: Implementing Infinite Scroll
const useInfiniteScroll = (fetchMore, hasMore, loading) => {
const [isFetching, setIsFetching] = useState(false);
useEffect(() => {
const handleScroll = () => {
if (
window.innerHeight + document.documentElement.scrollTop !==
document.documentElement.offsetHeight ||
isFetching
)
return;
if (hasMore && !loading) {
setIsFetching(true);
}
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [isFetching, hasMore, loading]);
useEffect(() => {
if (!isFetching) return;
fetchMore().finally(() => setIsFetching(false));
}, [isFetching, fetchMore]);
return [isFetching, setIsFetching];
};
const InfiniteScrollList = () => {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [loading, setLoading] = useState(false);
const fetchMoreItems = useCallback(async () => {
setLoading(true);
try {
const response = await fetch(`/api/items?page=${page}&limit=20`);
const newItems = await response.json();
if (newItems.length === 0) {
setHasMore(false);
} else {
setItems((prev) => [...prev, ...newItems]);
setPage((prev) => prev + 1);
}
} catch (error) {
console.error("Failed to fetch items:", error);
} finally {
setLoading(false);
}
}, [page]);
const [isFetching] = useInfiniteScroll(fetchMoreItems, hasMore, loading);
useEffect(() => {
fetchMoreItems();
}, []); // Initial load
return (
<div>
{items.map((item) => (
<div key={item.id} className="item">
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
))}
{(loading || isFetching) && <div>Loading more items...</div>}
{!hasMore && <div>No more items to load</div>}
</div>
);
};
Advanced Topics to Master
1. React Concurrent Features Deep Dive
// Time Slicing Example
const ExpensiveList = ({ items, searchTerm }) => {
const [isPending, startTransition] = useTransition();
const [filteredItems, setFilteredItems] = useState(items);
const handleSearch = (term) => {
startTransition(() => {
// This expensive operation won't block the UI
const filtered = items.filter(
(item) =>
item.name.toLowerCase().includes(term.toLowerCase()) ||
item.description.toLowerCase().includes(term.toLowerCase())
);
setFilteredItems(filtered);
});
};
return (
<div>
<input
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search items..."
/>
{isPending && <div>Searching...</div>}
<div className="items-grid">
{filteredItems.map((item) => (
<ExpensiveItem key={item.id} item={item} />
))}
</div>
</div>
);
};
2. Custom Hook Patterns
// Compound Hook Pattern
const useFormValidation = (initialValues, validationRules) => {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const [touched, setTouched] = useState({});
const validate = useCallback(
(fieldName, value) => {
const rule = validationRules[fieldName];
if (!rule) return "";
if (rule.required && !value) {
return "This field is required";
}
if (rule.minLength && value.length < rule.minLength) {
return `Minimum length is ${rule.minLength}`;
}
if (rule.pattern && !rule.pattern.test(value)) {
return rule.message || "Invalid format";
}
return "";
},
[validationRules]
);
const setValue = useCallback(
(name, value) => {
setValues((prev) => ({ ...prev, [name]: value }));
const error = validate(name, value);
setErrors((prev) => ({ ...prev, [name]: error }));
},
[validate]
);
const setTouchedField = useCallback((name) => {
setTouched((prev) => ({ ...prev, [name]: true }));
}, []);
const isValid = useMemo(() => {
return Object.values(errors).every((error) => !error);
}, [errors]);
const reset = useCallback(() => {
setValues(initialValues);
setErrors({});
setTouched({});
}, [initialValues]);
return {
values,
errors,
touched,
setValue,
setTouchedField,
isValid,
reset,
};
};
// Usage
const RegistrationForm = () => {
const { values, errors, touched, setValue, setTouchedField, isValid, reset } =
useFormValidation(
{ email: "", password: "", confirmPassword: "" },
{
email: {
required: true,
pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: "Please enter a valid email",
},
password: {
required: true,
minLength: 8,
},
confirmPassword: {
required: true,
validate: (value) =>
value === values.password ? "" : "Passwords must match",
},
}
);
return (
<form onSubmit={handleSubmit}>
<div>
<input
type="email"
value={values.email}
onChange={(e) => setValue("email", e.target.value)}
onBlur={() => setTouchedField("email")}
placeholder="Email"
/>
{touched.email && errors.email && <span>{errors.email}</span>}
</div>
<div>
<input
type="password"
value={values.password}
onChange={(e) => setValue("password", e.target.value)}
onBlur={() => setTouchedField("password")}
placeholder="Password"
/>
{touched.password && errors.password && <span>{errors.password}</span>}
</div>
<button type="submit" disabled={!isValid}>
Register
</button>
</form>
);
};
Frequently Asked React Interview Questions by Experience Level
Entry Level (0-2 years)
- What is React and why use it?
- Difference between props and state
- What is JSX?
- Component lifecycle methods
- What are React Hooks?
- Handling events in React
- Conditional rendering techniques
Mid Level (2-5 years)
- Advanced hooks usage (useCallback, useMemo, useRef)
- State management patterns
- Performance optimization techniques
- Error boundaries implementation
- Testing React components
- Code splitting and lazy loading
- Custom hooks development
Senior Level (5+ years)
- React architecture decisions
- Advanced patterns (HOCs, Render Props, Compound Components)
- React internals (Fiber, Reconciliation)
- Performance monitoring and optimization
- Micro-frontend architecture with React
- Server-side rendering strategies
- Team lead and mentoring approaches
React Interview Red Flags to Avoid
- Not understanding basic concepts like the difference between props and state
- Overusing useEffect for everything instead of appropriate hooks
- Ignoring performance implications of re-renders
- Not handling edge cases in code examples
- Using outdated patterns like class components for new development
- Poor error handling in async operations
- Not considering accessibility in component design
Conclusion
React.js continues to evolve rapidly, with new features and patterns emerging regularly. Success in React interviews requires not just theoretical knowledge but practical experience building real applications. Focus on understanding core concepts deeply, stay updated with the latest features, and practice building projects that demonstrate your skills.
The key to excelling in React interviews is combining strong fundamentals with awareness of modern patterns and performance considerations. Practice regularly, build projects, and stay connected with the React community to keep your skills sharp and current.
Remember that interviews are not just about getting the right answer, but demonstrating your problem-solving approach, communication skills, and ability to work with a team. Good luck with your React.js interview preparation!
Resources for Continued Learning
- Official React Documentation: https://react.dev
- React Blog: Stay updated with latest announcements
- React Conference Talks: Watch presentations from React Conf
- Open Source Projects: Contribute to React ecosystem projects
- Practice Platforms: Build projects on CodeSandbox, CodePen
- Community: Join React communities on Discord, Reddit, Stack Overflow
This guide covers the most current React.js interview trends and questions for 2025. Keep practicing and stay updated with the latest React developments for interview success.