React Interview Questions - Whiteboard
Fundamental Concepts
1. What is Virtual DOM and how does it work?
Answer: The Virtual DOM is a lightweight JavaScript representation of the actual DOM. React maintains a virtual copy and uses a diffing algorithm to:
- Compare new virtual DOM with previous version
- Calculate minimal changes needed
- Batch update only changed parts to real DOM
This is faster than direct DOM manipulation because DOM operations are expensive.
2. Explain React's reconciliation process
Answer: Reconciliation is how React updates the DOM. When state changes:
- React creates new Virtual DOM tree
- Compares with previous tree (diffing)
- Determines minimum number of operations
- Updates only changed nodes in real DOM
Key assumptions:
- Different elements = different trees
- Stable keys identify list items
3. What are keys in React and why are they important?
Answer: Keys help React identify which items changed, added, or removed. They should be:
- Stable (don't change between renders)
- Unique among siblings
- Not random or index (unless list is static)
// ❌ Bad
{
items.map((item, index) => <Item key={index} />);
}
// ✅ Good
{
items.map(item => <Item key={item.id} />);
}
Hooks
4. Explain useState and when to use useReducer instead
Answer:
- useState: Simple state, independent values
- useReducer: Complex state with multiple sub-values, state logic that involves previous state
// useState - simple
const [count, setCount] = useState(0);
// useReducer - complex
const [state, dispatch] = useReducer(reducer, initialState);
5. What is the difference between useMemo and useCallback?
Answer:
- useMemo: Memoizes computed VALUE
- useCallback: Memoizes FUNCTION reference
const value = useMemo(() => expensiveCalc(a, b), [a, b]);
const callback = useCallback(() => doSomething(), []);
6. Explain useEffect cleanup and when it runs
Answer: Cleanup runs:
- Before effect runs again (dependencies changed)
- When component unmounts
useEffect(() => {
const subscription = subscribe();
return () => {
subscription.unsubscribe(); // Cleanup
};
}, []);
Component Patterns
7. Controlled vs Uncontrolled Components
Answer: Controlled: React controls form state
const [value, setValue] = useState('');
<input value={value} onChange={e => setValue(e.target.value)} />;
Uncontrolled: DOM controls state via refs
const ref = useRef();
<input ref={ref} />;
// Access via ref.current.value
8. When to use Context vs Props?
Answer: Props:
- Parent to direct child
- 1-2 levels deep
- Explicit data flow
Context:
- Deep component trees
- Global state (theme, auth, language)
- Avoid prop drilling
Performance
9. How to prevent unnecessary re-renders?
Answer:
- React.memo - Memoize component
- useMemo - Memoize values
- useCallback - Memoize functions
- Keys - Proper list keys
- Code splitting - Lazy load
- Virtualization - Long lists
10. What causes infinite loops in useEffect?
Answer: Common causes:
- Missing dependency array
- Objects/arrays in dependencies (new reference each render)
- Setting state that's in dependencies
// ❌ Infinite loop
useEffect(() => {
setCount(count + 1);
}); // No deps!
// ❌ Infinite loop
useEffect(() => {
setCount(count + 1);
}, [count]); // count changes → effect runs → count changes...
// ✅ Correct
useEffect(() => {
setCount(c => c + 1);
}, []); // Empty deps
Advanced
11. Explain React Fiber
Answer: Fiber is React's reconciliation engine that enables:
- Incremental rendering (pause/resume work)
- Priority-based updates
- Concurrent features
- Better error handling
12. What are Server Components?
Answer: React Server Components (React 19):
- Run on server only
- Zero bundle size
- Direct database access
- Automatic code splitting
- Better performance
Coding Questions
13. Implement usePrevious hook
function usePrevious\<T\>(value: T): T | undefined {
const ref = useRef\<T\>();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
14. Implement useDebounce hook
function useDebounce\<T\>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
15. Implement useToggle hook
function useToggle(initial: boolean = false) {
const [value, setValue] = useState(initial);
const toggle = useCallback(() => setValue(v => !v), []);
return [value, toggle] as const;
}
System Design
16. Design a scalable React application architecture
Answer:
src/
├── components/
│ ├── common/ # Reusable UI
│ └── features/ # Feature-specific
├── pages/ # Route components
├── hooks/ # Custom hooks
├── services/ # API calls
├── store/ # State management
├── types/ # TypeScript types
├── utils/ # Utilities
└── tests/ # Test files
17. How to handle authentication in React?
Answer:
- Context for auth state
- Protected routes
- Token storage (httpOnly cookies or secure storage)
- Refresh token logic
- Redirect on auth failure
<Route
path='/dashboard'
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
Best Practices
- Use TypeScript for type safety
- Keep components small and focused
- Extract custom hooks for reusable logic
- Use proper keys in lists
- Memoize expensive calculations
- Handle loading and error states
- Test components with React Testing Library
- Optimize bundle size with code splitting
- Use ESLint and Prettier
- Follow naming conventions