REACT INTERVIEW QUESTIONS - 3 YEARS EXPERIENCE
1. ADVANCED HOOKS
Q: Explain useReducer and when to use it over useState
A:
useReducer is useful for complex state logic that involves multiple sub-values or
when the next state depends on the previous one.
Example:
```jsx
import React, { useReducer } from 'react';
const todoReducer = (state, action) => {
switch ([Link]) {
case 'ADD_TODO':
return {
...state,
todos: [...[Link], {
id: [Link](),
text: [Link],
completed: false
}]
};
case 'TOGGLE_TODO':
return {
...state,
todos: [Link](todo =>
[Link] === [Link]
? { ...todo, completed: ![Link] }
: todo
)
};
default:
return state;
}
};
function TodoApp() {
const [state, dispatch] = useReducer(todoReducer, { todos: [] });
const addTodo = (text) => {
dispatch({ type: 'ADD_TODO', payload: text });
};
const toggleTodo = (id) => {
dispatch({ type: 'TOGGLE_TODO', payload: id });
};
return (
<div>
<button onClick={() => addTodo('New todo')}>Add Todo</button>
{[Link](todo => (
<div key={[Link]} onClick={() => toggleTodo([Link])}>
{[Link]} - {[Link] ? 'Done' : 'Pending'}
</div>
))}
</div>
);
}
```
Q: Create custom hooks for common functionality
A:
```jsx
// Custom hook for API calls
function useApi(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
const result = await [Link]();
setData(result);
} catch (err) {
setError([Link]);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Custom hook for localStorage
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = [Link](key);
return item ? [Link](item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
[Link](key, [Link](valueToStore));
} catch (error) {
[Link](error);
}
};
return [storedValue, setValue];
}
```
2. CONTEXT API AND STATE MANAGEMENT
Q: Implement a theme context with React Context API
A:
```jsx
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
const themeStyles = {
light: { backgroundColor: '#ffffff', color: '#333333' },
dark: { backgroundColor: '#333333', color: '#ffffff' }
};
return (
<[Link] value={{ theme, toggleTheme, styles:
themeStyles[theme] }}>
{children}
</[Link]>
);
}
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
function Header() {
const { theme, toggleTheme, styles } = useTheme();
return (
<header style={styles}>
<h1>My App</h1>
<button onClick={toggleTheme}>
Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
</button>
</header>
);
}
```
3. PERFORMANCE OPTIMIZATION
Q: Explain [Link], useMemo, and useCallback
A:
```jsx
import React, { useState, useMemo, useCallback, memo } from 'react';
// Memoized component
const ExpensiveComponent = memo(({ data, onItemClick }) => {
[Link]('ExpensiveComponent rendered');
return (
<div>
{[Link](item => (
<div key={[Link]} onClick={() => onItemClick([Link])}>
{[Link]} - {[Link]}
</div>
))}
</div>
);
});
function PerformanceApp() {
const [users, setUsers] = useState([
{ id: 1, name: 'John', email: 'john@[Link]' },
{ id: 2, name: 'Jane', email: 'jane@[Link]' }
]);
const [count, setCount] = useState(0);
// Memoized expensive calculation
const expensiveData = useMemo(() => {
[Link]('Computing expensive data...');
return [Link](user => ({
id: [Link],
name: [Link],
value: [Link] * [Link]
}));
}, [users]);
// Memoized callback
const handleItemClick = useCallback((itemId) => {
[Link]('Item clicked:', itemId);
}, []);
return (
<div>
<button onClick={() => setCount(prev => prev + 1)}>
Count: {count}
</button>
<ExpensiveComponent
data={expensiveData}
onItemClick={handleItemClick}
/>
</div>
);
}
```
4. ADVANCED PATTERNS
Q: Implement Render Props pattern
A:
```jsx
function DataFetcher({ url, render }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
const result = await [Link]();
setData(result);
} catch (err) {
setError([Link]);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return render({ data, loading, error });
}
// Usage
<DataFetcher
url="/api/users"
render={({ data, loading, error }) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (!data) return <div>No data</div>;
return (
<ul>
{[Link](user => (
<li key={[Link]}>{[Link]}</li>
))}
</ul>
);
}}
/>
```
5. ERROR BOUNDARIES
Q: Implement an error boundary with retry functionality
A:
```jsx
class ErrorBoundary extends [Link] {
constructor(props) {
super(props);
[Link] = {
hasError: false,
error: null,
retryCount: 0
};
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
[Link]('Error caught by boundary:', error, errorInfo);
}
handleRetry = () => {
[Link](prev => ({
hasError: false,
error: null,
retryCount: [Link] + 1
}));
};
render() {
if ([Link]) {
return (
<div>
<h2>Something went wrong!</h2>
<p>We're sorry, but something unexpected happened.</p>
{[Link] < 3 && (
<button onClick={[Link]}>
Try Again ({[Link] + 1}/3)
</button>
)}
<button onClick={() => [Link]()}>
Reload Page
</button>
</div>
);
}
return [Link];
}
}
```
6. TESTING REACT COMPONENTS
Q: How do you test React components?
A:
```jsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
// Component to test
function LoginForm({ onSubmit, loading = false }) {
const [formData, setFormData] = useState({ email: '', password: '' });
const [errors, setErrors] = useState({});
const handleSubmit = (e) => {
[Link]();
const newErrors = {};
if (![Link]) [Link] = 'Email is required';
if (![Link]) [Link] = 'Password is required';
if ([Link](newErrors).length === 0) {
onSubmit(formData);
} else {
setErrors(newErrors);
}
};
return (
<form onSubmit={handleSubmit} data-testid="login-form">
<input
name="email"
value={[Link]}
onChange={(e) => setFormData(prev => ({ ...prev, email: [Link] }))}
data-testid="email-input"
/>
{[Link] && <span data-testid="email-error">{[Link]}</span>}
<input
name="password"
type="password"
value={[Link]}
onChange={(e) => setFormData(prev => ({ ...prev, password:
[Link] }))}
data-testid="password-input"
/>
{[Link] && <span
data-testid="password-error">{[Link]}</span>}
<button type="submit" disabled={loading} data-testid="submit-button">
{loading ? 'Logging in...' : 'Login'}
</button>
</form>
);
}
// Test
describe('LoginForm', () => {
const mockOnSubmit = [Link]();
test('shows validation errors for empty fields', async () => {
render(<LoginForm onSubmit={mockOnSubmit} />);
const submitButton = [Link]('submit-button');
[Link](submitButton);
await waitFor(() => {
expect([Link]('email-error')).toHaveTextContent('Email is
required');
expect([Link]('password-error')).toHaveTextContent('Password is
required');
});
});
test('submits form with valid data', async () => {
render(<LoginForm onSubmit={mockOnSubmit} />);
[Link]([Link]('email-input'), {
target: { value: 'test@[Link]' }
});
[Link]([Link]('password-input'), {
target: { value: 'password123' }
});
[Link]([Link]('submit-button'));
await waitFor(() => {
expect(mockOnSubmit).toHaveBeenCalledWith({
email: 'test@[Link]',
password: 'password123'
});
});
});
});
```
7. PRACTICAL CODING EXERCISES
Q: Create a reusable Modal component with portal
A:
```jsx
import React, { useEffect } from 'react';
import { createPortal } from 'react-dom';
function Modal({ isOpen, onClose, title, children }) {
useEffect(() => {
const handleEscape = (e) => {
if ([Link] === 'Escape') {
onClose();
}
};
if (isOpen) {
[Link]('keydown', handleEscape);
[Link] = 'hidden';
}
return () => {
[Link]('keydown', handleEscape);
[Link] = 'unset';
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return createPortal(
<div style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1000
}}>
<div style={{
backgroundColor: 'white',
padding: '2rem',
borderRadius: '8px',
maxWidth: '500px',
width: '90%'
}}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems:
'center' }}>
<h2>{title}</h2>
<button onClick={onClose}>×</button>
</div>
{children}
</div>
</div>,
[Link]
);
}
// Usage
function 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 proceed?</p>
<button onClick={() => setIsModalOpen(false)}>Cancel</button>
<button onClick={() => {
[Link]('Confirmed');
setIsModalOpen(false);
}}>Confirm</button>
</Modal>
</div>
);
}
```
Q: Implement infinite scrolling with React
A:
```jsx
import React, { useState, useEffect, useRef, useCallback } from 'react';
function InfiniteScroll({ fetchData, renderItem }) {
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const [page, setPage] = useState(1);
const observer = useRef();
const lastItemRef = useCallback(node => {
if (loading) return;
if ([Link]) [Link]();
[Link] = new IntersectionObserver(entries => {
if (entries[0].isIntersecting && hasMore) {
setPage(prevPage => prevPage + 1);
}
});
if (node) [Link](node);
}, [loading, hasMore]);
useEffect(() => {
const loadData = async () => {
setLoading(true);
try {
const newData = await fetchData(page);
if ([Link] === 0) {
setHasMore(false);
} else {
setItems(prev => [...prev, ...newData]);
}
} catch (error) {
[Link]('Error loading data:', error);
} finally {
setLoading(false);
}
};
loadData();
}, [page, fetchData]);
return (
<div>
{[Link]((item, index) => {
if ([Link] === index + 1) {
return (
<div key={[Link]} ref={lastItemRef}>
{renderItem(item)}
</div>
);
} else {
return (
<div key={[Link]}>
{renderItem(item)}
</div>
);
}
})}
{loading && <div>Loading...</div>}
{!hasMore && <div>No more items</div>}
</div>
);
}
// Usage
function App() {
const fetchData = async (page) => {
// Simulate API call
const response = await fetch(`/api/items?page=${page}&limit=10`);
return [Link]();
};
const renderItem = (item) => (
<div style={{ padding: '1rem', border: '1px solid #ccc', margin: '0.5rem' }}>
<h3>{[Link]}</h3>
<p>{[Link]}</p>
</div>
);
return (
<InfiniteScroll fetchData={fetchData} renderItem={renderItem} />
);
}
```
COMMON INTERVIEW TIPS FOR 3 YEARS EXPERIENCE:
- Understand advanced hooks (useReducer, useMemo, useCallback)
- Know how to create and use custom hooks
- Be comfortable with Context API and state management
- Understand performance optimization techniques
- Know testing strategies and tools
- Be able to implement design patterns
- Understand error boundaries and error handling
- Know how to optimize component re-renders
- Be familiar with code splitting and lazy loading
- Understand the difference between controlled and uncontrolled components