React.
js & JavaScript Interview Problems - 3+ Years Experience
JavaScript Fundamentals
1. Closures and Scope
javascript
// Problem: What will this code output?
function outerFunction(x) {
return function innerFunction(y) {
return x + y;
};
}
const add5 = outerFunction(5);
console.log(add5(3)); // ?
// Answer: 8
// Explanation: The inner function has access to the outer function's variables (closure)
2. Hoisting
javascript
// Problem: What will this code output?
console.log(a); // ?
console.log(b); // ?
console.log(c); // ?
var a = 1;
let b = 2;
const c = 3;
// Answer:
// undefined (var is hoisted but not initialized)
// ReferenceError: Cannot access 'b' before initialization
// ReferenceError: Cannot access 'c' before initialization
3. Event Loop & Async
javascript
// Problem: What's the output order?
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
// Answer: 1, 4, 3, 2
// Explanation: Promises have higher priority than setTimeout in the event loop
4. Array Methods Implementation
javascript
// Problem: Implement your own map function
Array.prototype.myMap = function(callback) {
const result = [];
for (let i = 0; i < this.length; i++) {
result.push(callback(this[i], i, this));
}
return result;
};
// Usage
const numbers = [1, 2, 3, 4];
const doubled = numbers.myMap(x => x * 2);
console.log(doubled); // [2, 4, 6, 8]
5. Debouncing
javascript
// Problem: Implement a debounce function
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Usage
const debouncedSearch = debounce((query) => {
console.log('Searching for:', query);
}, 300);
6. Throttling
javascript
// Problem: Implement a throttle function
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
React Fundamentals
7. useState Hook
javascript
// Problem: Create a counter component with increment/decrement
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
8. useEffect Hook
javascript
// Problem: Fetch data and handle cleanup
import React, { useState, useEffect } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let isCancelled = false;
async function fetchUser() {
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
if (!isCancelled) {
setUser(userData);
setLoading(false);
}
} catch (error) {
if (!isCancelled) {
console.error('Error fetching user:', error);
setLoading(false);
}
}
}
fetchUser();
return () => {
isCancelled = true;
};
}, [userId]);
if (loading) return <div>Loading...</div>;
return <div>{user?.name}</div>;
}
9. Custom Hooks
javascript
// Problem: Create a custom hook for local storage
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error('Error reading localStorage:', error);
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error('Error setting localStorage:', error);
}
};
return [storedValue, setValue];
}
// Usage
function App() {
const [name, setName] = useLocalStorage('name', '');
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
);
}
10. Context API
javascript
// Problem: Create a theme context
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
// Usage
function App() {
const { theme, toggleTheme } = useTheme();
return (
<div className={`app ${theme}`}>
<button onClick={toggleTheme}>
Switch to {theme === 'light' ? 'dark' : 'light'} mode
</button>
</div>
);
}
Intermediate React Patterns
11. Higher-Order Components (HOC)
javascript
// Problem: Create a HOC for loading states
import React from 'react';
function withLoading(WrappedComponent) {
return function WithLoadingComponent(props) {
if (props.isLoading) {
return <div>Loading...</div>;
}
return <WrappedComponent {...props} />;
};
}
// Usage
const UserList = ({ users }) => (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
const UserListWithLoading = withLoading(UserList);
// In parent component
<UserListWithLoading users={users} isLoading={loading} />
12. Render Props Pattern
javascript
// Problem: Create a render props component for mouse tracking
import React, { useState, useEffect } from 'react';
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY });
};
window.addEventListener('mousemove', handleMouseMove);
return () => window.removeEventListener('mousemove', handleMouseMove);
}, []);
return render(position);
}
// Usage
function App() {
return (
<MouseTracker
render={({ x, y }) => (
<div>Mouse position: {x}, {y}</div>
)}
/>
);
}
13. useReducer Hook
javascript
// Problem: Create a todo app with useReducer
import React, { useReducer } from 'react';
const initialState = { todos: [] };
function todoReducer(state, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, { id: Date.now(), text: action.payload, completed: false }]
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo
)
};
case 'DELETE_TODO':
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload)
};
default:
return state;
}
}
function TodoApp() {
const [state, dispatch] = useReducer(todoReducer, initialState);
const [inputValue, setInputValue] = useState('');
const addTodo = () => {
if (inputValue.trim()) {
dispatch({ type: 'ADD_TODO', payload: inputValue });
setInputValue('');
}
};
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>Add Todo</button>
{state.todos.map(todo => (
<div key={todo.id}>
<span
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
onClick={() => dispatch({ type: 'TOGGLE_TODO', payload: todo.id })}
>
{todo.text}
</span>
<button onClick={() => dispatch({ type: 'DELETE_TODO', payload: todo.id })}>
Delete
</button>
</div>
))}
</div>
);
}
Advanced React Concepts
14. useMemo and useCallback
javascript
// Problem: Optimize expensive calculations and prevent unnecessary re-renders
import React, { useState, useMemo, useCallback } from 'react';
function ExpensiveComponent({ items, onItemClick }) {
const expensiveValue = useMemo(() => {
console.log('Computing expensive value...');
return items.reduce((sum, item) => sum + item.value, 0);
}, [items]);
const handleClick = useCallback((item) => {
onItemClick(item);
}, [onItemClick]);
return (
<div>
<p>Total: {expensiveValue}</p>
{items.map(item => (
<button key={item.id} onClick={() => handleClick(item)}>
{item.name}
</button>
))}
</div>
);
}
// Parent component
function Parent() {
const [items, setItems] = useState([
{ id: 1, name: 'Item 1', value: 10 },
{ id: 2, name: 'Item 2', value: 20 }
]);
const [count, setCount] = useState(0);
const handleItemClick = useCallback((item) => {
console.log('Item clicked:', item);
}, []);
return (
<div>
<button onClick={() => setCount(count + 1)}>Count: {count}</button>
<ExpensiveComponent items={items} onItemClick={handleItemClick} />
</div>
);
}
15. Error Boundaries
javascript
// Problem: Create an error boundary component
import React from 'react';
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) {
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Something went wrong</h2>
<p>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false, error: null })}>
Try again
</button>
</div>
);
}
return this.props.children;
}
}
// Usage
function App() {
return (
<ErrorBoundary>
<ComponentThatMightError />
</ErrorBoundary>
);
}
16. Lazy Loading and Suspense
javascript
// Problem: Implement lazy loading with Suspense
import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading component...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
// LazyComponent.js
const LazyComponent = () => {
return <div>This component was loaded lazily!</div>;
};
export default LazyComponent;
Performance Optimization
17. React.memo
javascript
// Problem: Prevent unnecessary re-renders with React.memo
import React, { memo } from 'react';
const ExpensiveChildComponent = memo(({ name, value }) => {
console.log('ExpensiveChildComponent rendered');
return (
<div>
<p>{name}: {value}</p>
</div>
);
});
// With custom comparison
const OptimizedComponent = memo(({ user, settings }) => {
return (
<div>
<p>{user.name}</p>
<p>{settings.theme}</p>
</div>
);
}, (prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id &&
prevProps.settings.theme === nextProps.settings.theme;
});
18. Virtual Scrolling
javascript
// Problem: Implement basic virtual scrolling for large lists
import React, { useState, useEffect, useRef } from 'react';
function VirtualList({ items, itemHeight = 50, containerHeight = 400 }) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef();
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(containerHeight / itemHeight) + 1,
items.length
);
const visibleItems = items.slice(startIndex, endIndex);
const handleScroll = (e) => {
setScrollTop(e.target.scrollTop);
};
return (
<div
ref={containerRef}
style={{ height: containerHeight, overflow: 'auto' }}
onScroll={handleScroll}
>
<div style={{ height: items.length * itemHeight, position: 'relative' }}>
{visibleItems.map((item, index) => (
<div
key={startIndex + index}
style={{
position: 'absolute',
top: (startIndex + index) * itemHeight,
height: itemHeight,
width: '100%',
border: '1px solid #ccc'
}}
>
{item}
</div>
))}
</div>
</div>
);
}
Testing Questions
19. Unit Testing with Jest and React Testing Library
javascript
// Problem: Write tests for a component
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import '@testing-library/jest-dom';
import Counter from './Counter';
describe('Counter Component', () => {
test('renders initial count', () => {
render(<Counter />);
expect(screen.getByText('Count: 0')).toBeInTheDocument();
});
test('increments count when button is clicked', () => {
render(<Counter />);
const incrementButton = screen.getByText('+');
fireEvent.click(incrementButton);
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
test('decrements count when button is clicked', () => {
render(<Counter />);
const decrementButton = screen.getByText('-');
fireEvent.click(decrementButton);
expect(screen.getByText('Count: -1')).toBeInTheDocument();
});
});
Common Algorithm Problems
20. Flatten Array
javascript
// Problem: Flatten a nested array
function flattenArray(arr) {
return arr.reduce((flat, item) => {
return flat.concat(Array.isArray(item) ? flattenArray(item) : item);
}, []);
}
// Alternative with flat()
const flattenWithBuiltIn = (arr) => arr.flat(Infinity);
// Test
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(flattenArray(nested)); // [1, 2, 3, 4, 5, 6]
21. Deep Clone Object
javascript
// Problem: Deep clone an object
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof Array) return obj.map(item => deepClone(item));
if (typeof obj === 'object') {
const cloned = {};
Object.keys(obj).forEach(key => {
cloned[key] = deepClone(obj[key]);
});
return cloned;
}
}
// Test
const original = { a: 1, b: { c: 2, d: [3, 4] } };
const cloned = deepClone(original);
cloned.b.c = 999;
console.log(original.b.c); // 2 (unchanged)
22. Memoization
javascript
// Problem: Implement memoization for expensive functions
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// Usage with Fibonacci
const fibonacci = memoize((n) => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
Interview Tips
Key Areas to Focus On:
1. JavaScript Fundamentals: Closures, hoisting, event loop, promises
2. React Hooks: useState, useEffect, useContext, useReducer, useMemo, useCallback
3. Component Patterns: HOCs, render props, compound components
4. Performance: Memoization, lazy loading, virtual scrolling
5. Testing: Unit tests, integration tests, mocking
6. State Management: Context API, Redux patterns
7. Error Handling: Error boundaries, try-catch blocks
8. Async Operations: Fetch, axios, handling loading states
Common Follow-up Questions:
"How would you optimize this component?"
"What are the trade-offs of this approach?"
"How would you test this functionality?"
"What happens if this API call fails?"
"How would you handle this at scale?"
Practice Strategy:
1. Start with JavaScript fundamentals
2. Build small React components from scratch
3. Implement common patterns and hooks
4. Focus on performance optimization techniques
5. Practice explaining your thought process
6. Learn to identify and handle edge cases
Remember: Interviewers want to see your problem-solving approach, not just the final solution. Always
explain your thinking process!