React Interview Cheat Sheet
Complete React reference covering Hooks, Context API, performance optimization, and modern React patterns.
Overview
Comprehensive React interview guide covering all hooks, Context API, performance optimization with memo/useMemo/useCallback, component patterns, and common React interview scenarios.
Reference Content
π Core Concepts
Class Components:
ββ MOUNTING ββββββββββββββ ββ UPDATING ββββββββββββββ ββ UNMOUNTING βββ
β constructor() β β componentDidUpdate() β β componentWill β
β render() β β render() β β Unmount() β
β componentDidMount() β β getSnapshotBeforeUpdateβ ββββββββββββββββββ
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββFunction Components with Hooks:
ββ MOUNT ββββββ ββ UPDATE ββββββ ββ UNMOUNT βββββ
β useState() β β re-render β β cleanup β
β useEffect() β β useEffect() β β functions β
βββββββββββββββ ββββββββββββββββ ββββββββββββββββ
Performance Optimization
import { memo, useState } from 'react';// Expensive component that should only re-render when props change
const ExpensiveChild = memo(function ExpensiveChild({ name, age, hobbies }) {
console.log('ExpensiveChild rendered');
// Expensive computation
const expensiveValue = useMemo(() => {
return hobbies.map(hobby => hobby.toUpperCase()).join(', ');
}, [hobbies]);
return (
{name} ({age})
Hobbies: {expensiveValue}
);
});// Custom comparison function
const SmartComponent = memo(function SmartComponent({ user, settings }) {
return
{user.name} - {settings.theme};
}, (prevProps, nextProps) => {
// Return true if props are equal (skip re-render)
// Return false if props are different (re-render)
return (
prevProps.user.id === nextProps.user.id &&
prevProps.settings.theme === nextProps.settings.theme
);
});function Parent() {
const [count, setCount] = useState(0);
const [user] = useState({ name: 'John', age: 30, hobbies: ['reading', 'coding'] });
// Child won't re-render when count changes
return (
Count: {count}
);
}Advanced Hooks
import { useLayoutEffect, useRef, useState } from 'react';function Tooltip({ children, text }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
const tooltipRef = useRef();
const triggerRef = useRef();
// useLayoutEffect runs synchronously after DOM mutations
// but before the browser paints (prevents flicker)
useLayoutEffect(() => {
if (tooltipRef.current && triggerRef.current) {
const triggerRect = triggerRef.current.getBoundingClientRect();
const tooltipRect = tooltipRef.current.getBoundingClientRect();
// Calculate position to avoid viewport overflow
let x = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;
let y = triggerRect.top - tooltipRect.height - 10;
if (x < 0) x = 10;
if (x + tooltipRect.width > window.innerWidth) {
x = window.innerWidth - tooltipRect.width - 10;
}
if (y < 0) {
y = triggerRect.bottom + 10;
}
setPosition({ x, y });
}
});
return (
<>
{children}
ref={tooltipRef}
className="tooltip"
style={{
position: 'fixed',
left: position.x,
top: position.y,
zIndex: 1000
}}
>
{text}
>
);
}Component Patterns
// HOC for loading states
function withLoading(WrappedComponent) {
return function WithLoadingComponent(props) {
if (props.loading) {
return Loading...;
}
return ;
};
}// HOC for authentication
function withAuth(WrappedComponent, { redirectTo = '/login' } = {}) {
return function WithAuthComponent(props) {
const { user } = useContext(AuthContext);
if (!user) {
return ;
}
return ;
};
}
// Usage
const UserProfile = withAuth(withLoading(function UserProfile({ user, loading }) {
return
Welcome, {user.name}!;
}));Error Handling
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null, errorInfo: null };
}
static getDerivedStateFromError(error) {
// Update state to show fallback UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// Log error to error reporting service
console.error('Error caught by boundary:', error, errorInfo);
this.setState({ error, errorInfo });
}
render() {
if (this.state.hasError) {
return (
Something went wrong
Error details
{this.state.error && this.state.error.toString()}
{this.state.errorInfo.componentStack}
);
}
return this.props.children;
}
}// Functional error boundary (using third-party library like react-error-boundary)
import { ErrorBoundary } from 'react-error-boundary';
function ErrorFallback({ error, resetErrorBoundary }) {
return (
Oops! Something went wrong
Error: {error.message}
);
}function App() {
return (
FallbackComponent={ErrorFallback}
onError={(error, errorInfo) => {
console.error('Error logged:', error, errorInfo);
}}
onReset={() => {
// Reset any state that might be causing the error
}}
>
);
}
Common Interview Questions
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1); // Uses stale closure
setCount(count + 1); // Uses same stale value
console.log(count); // Still 0 (state hasn't updated yet)
};
return ;
}// Answer: Clicking increments by 1, not 2
// Solution: Use functional updates
const handleClick = () => {
setCount(prev => prev + 1);
setCount(prev => prev + 1);
};
Performance Best Practices
- β Use React.memo for pure components
- β Use useMemo for expensive computations
- β Use useCallback for event handlers passed to children
- β Avoid creating objects/arrays in JSX
- β Use keys properly in lists
- β Lazy load components with React.Suspense
- β Split large bundles with React.lazy
- β Use React DevTools Profiler
- β Implement proper error boundaries
- β Avoid deeply nested context providers