Get Started
Freshers Mega-Guide: 50+ Q&A

50+ Essential React Interview Questions for Freshers (2026)

The ultimate guide for entry-level React developers. Over 50 carefully selected questions and answers to help freshers master their technical interviews.

β€’β€’interview-prep

    Introduction: The Importance of Mid-Level React Developers

    In today's fast-paced web development landscape, React has emerged as one of the most popular JavaScript libraries for building user interfaces. Mid-level React developers represent a crucial segment of the development workforceβ€”they have moved beyond basic concepts but aren't yet senior architects. These professionals typically have 2-4 years of experience and are capable of handling complex components, state management, and performance optimization with minimal supervision.

    This comprehensive guide provides interviewers and candidates with an in-depth look at React mid-level interview questions, complete with explanations, code examples, and best practices. Whether you're preparing for an interview or conducting one, this 2500+ word resource will help you navigate the technical landscape of mid-level React development.

    Core React Concepts and Advanced JSX

    1. Explain React's Virtual DOM and Reconciliation Process

    Expected Answer Depth:
    A mid-level candidate should understand not just what the Virtual DOM is, but how it works and why it's efficient.

    Detailed Explanation:
    The Virtual DOM (VDOM) is a programming concept where an ideal or "virtual" representation of the UI is kept in memory and synced with the "real" DOM through a process called reconciliation. When component state changes, React:

    1. Creates a new virtual DOM tree

    2. Diffs it against the previous virtual DOM tree (reconciliation)

    3. Calculates the minimal set of DOM operations needed

    4. Batch updates the real DOM

    javascript
    // Example showing how React efficiently updates only what's necessary
    class EfficientList extends React.Component {
      state = { items: ['Item 1', 'Item 2', 'Item 3'] };
      
      updateList = () => {
        // React will efficiently update only the changed items
        this.setState({ items: ['Item 1', 'Item 2 Updated', 'Item 3', 'Item 4'] });
      };
      
      render() {
        return (
          <div>
            <ul>
              {this.state.items.map((item, index) => (
                <li key={index}>{item}</li>
              ))}
            </ul>
            <button onClick={this.updateList}>Update List</button>
          </div>
        );
      }
    }

    Follow-up Question: How does React's diffing algorithm work, and what's the significance of keys in lists?

    2. Component Lifecycle Methods in Class Components and Their Hooks Equivalents

    Expected Knowledge:
    Mid-level developers should understand lifecycle methods and their useEffect equivalents in functional components.

    Lifecycle Mapping Table:

    Class Component LifecycleFunctional Component Equivalent
    componentDidMountuseEffect(() => {}, [])
    componentDidUpdateuseEffect(() => {})
    componentWillUnmountuseEffect(() => { return () => {} }, [])
    shouldComponentUpdateReact.memo, useMemo
    getDerivedStateFromPropsuseState with useEffect
    javascript
    // Class component with lifecycle methods
    class UserProfile extends React.Component {
      componentDidMount() {
        console.log('Component mounted, fetching data...');
        this.fetchUserData();
      }
      
      componentDidUpdate(prevProps) {
        if (this.props.userId !== prevProps.userId) {
          console.log('User ID changed, refetching data...');
          this.fetchUserData();
        }
      }
      
      componentWillUnmount() {
        console.log('Component unmounting, cleaning up...');
        this.cleanup();
      }
      
      fetchUserData() { /* API call */ }
      cleanup() { /* Cleanup logic */ }
      
      render() {
        return <div>User Profile</div>;
      }
    }
    
    // Equivalent functional component with hooks
    function UserProfileFunctional({ userId }) {
      useEffect(() => {
        console.log('Component mounted, fetching data...');
        fetchUserData();
        
        return () => {
          console.log('Component unmounting, cleaning up...');
          cleanup();
        };
      }, []);
      
      useEffect(() => {
        console.log('User ID changed, refetching data...');
        fetchUserData();
      }, [userId]);
      
      const fetchUserData = () => { /* API call */ };
      const cleanup = () => { /* Cleanup logic */ };
      
      return <div>User Profile</div>;
    }

    State Management Patterns

    3. When to Use Redux vs Context API vs Local State

    Expected Analysis:
    A mid-level developer should understand the trade-offs between different state management solutions.

    Decision Framework:

    1. Local Component State (useState/useReducer):

      • Form inputs

      • UI toggle states

      • Component-specific data

    2. Context API:

      • Theme settings

      • User authentication status

      • Language preferences

      • Small to medium apps with simple state

    3. Redux (or similar libraries):

      • Large-scale applications

      • Complex state logic with multiple reducers

      • Need for time-travel debugging

      • State persistence requirements

      • When you need middleware (thunks, sagas)

    javascript
    // Context API Example for Theme Management
    const ThemeContext = React.createContext();
    
    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>
      );
    }
    
    // Custom hook for consuming theme
    function useTheme() {
      const context = useContext(ThemeContext);
      if (!context) {
        throw new Error('useTheme must be used within ThemeProvider');
      }
      return context;
    }
    
    // Component using the theme
    function ThemedButton() {
      const { theme, toggleTheme } = useTheme();
      
      return (
        <button 
          onClick={toggleTheme}
          style={{
            backgroundColor: theme === 'light' ? '#fff' : '#333',
            color: theme === 'light' ? '#000' : '#fff'
          }}
        >
          Toggle Theme
        </button>
      );
    }

    4. Advanced useState and useReducer Patterns

    Expected Understanding:
    Mid-level developers should know when to use useReducer over useState and understand complex state patterns.

    javascript
    // Complex state with useReducer
    const initialState = {
      loading: false,
      data: null,
      error: null,
      page: 1,
      totalPages: 1
    };
    
    function apiReducer(state, action) {
      switch (action.type) {
        case 'FETCH_START':
          return { ...state, loading: true, error: null };
        case 'FETCH_SUCCESS':
          return { 
            ...state, 
            loading: false, 
            data: action.payload.data,
            totalPages: action.payload.totalPages
          };
        case 'FETCH_ERROR':
          return { ...state, loading: false, error: action.payload };
        case 'SET_PAGE':
          return { ...state, page: action.payload };
        case 'UPDATE_ITEM':
          return {
            ...state,
            data: state.data.map(item => 
              item.id === action.payload.id ? action.payload : item
            )
          };
        default:
          throw new Error(`Unhandled action type: ${action.type}`);
      }
    }
    
    function DataFetcher() {
      const [state, dispatch] = useReducer(apiReducer, initialState);
      
      const fetchData = async (page) => {
        dispatch({ type: 'FETCH_START' });
        try {
          const response = await fetch(`/api/data?page=${page}`);
          const result = await response.json();
          dispatch({ type: 'FETCH_SUCCESS', payload: result });
        } catch (error) {
          dispatch({ type: 'FETCH_ERROR', payload: error.message });
        }
      };
      
      useEffect(() => {
        fetchData(state.page);
      }, [state.page]);
      
      // Component rendering logic...
    }

    Performance Optimization Techniques

    5. Memoization: React.memo, useMemo, and useCallback

    Expected Knowledge:
    Understanding when and how to use memoization techniques to prevent unnecessary re-renders.

    javascript
    // Performance optimization example
    const ExpensiveComponent = React.memo(function ExpensiveComponent({ items, onSelect }) {
      console.log('ExpensiveComponent rendering');
      
      // useMemo for expensive calculations
      const processedItems = useMemo(() => {
        console.log('Processing items...');
        return items.map(item => ({
          ...item,
          processed: expensiveComputation(item)
        }));
      }, [items]); // Only recalculate when items change
      
      // useCallback for stable function references
      const handleClick = useCallback((item) => {
        onSelect(item);
      }, [onSelect]);
      
      return (
        <div>
          {processedItems.map(item => (
            <MemoizedItem 
              key={item.id} 
              item={item}
              onClick={handleClick}
            />
          ))}
        </div>
      );
    });
    
    // Child component with React.memo
    const MemoizedItem = React.memo(function MemoizedItem({ item, onClick }) {
      console.log(`Item ${item.id} rendering`);
      return (
        <div onClick={() => onClick(item)}>
          {item.name}
        </div>
      );
    }, (prevProps, nextProps) => {
      // Custom comparison function
      return prevProps.item.id === nextProps.item.id && 
             prevProps.item.processed === nextProps.item.processed;
    });
    
    function expensiveComputation(item) {
      // Simulating expensive computation
      return item.value * Math.random();
    }

    6. Code Splitting and Lazy Loading

    Expected Implementation:
    Knowledge of dynamic imports and React.lazy for code splitting.

    javascript
    // Route-based code splitting
    import React, { Suspense, lazy } from 'react';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    import LoadingSpinner from './components/LoadingSpinner';
    
    // Lazy loaded components
    const Home = lazy(() => import('./pages/Home'));
    const Dashboard = lazy(() => import('./pages/Dashboard'));
    const Analytics = lazy(() => import('./pages/Analytics'));
    const Settings = lazy(() => import('./pages/Settings'));
    
    // Preload strategy for better UX
    const preloadComponent = (component) => {
      component.preload();
    };
    
    function App() {
      return (
        <Router>
          <Suspense fallback={<LoadingSpinner />}>
            <Switch>
              <Route exact path="/" component={Home} />
              <Route path="/dashboard" component={Dashboard} />
              <Route path="/analytics" component={Analytics} />
              <Route path="/settings" component={Settings} />
            </Switch>
          </Suspense>
          
          {/* Preload on hover for better UX */}
          <div 
            onMouseEnter={() => preloadComponent(Dashboard)}
            style={{ display: 'none' }}
          >
            Preload area
          </div>
        </Router>
      );
    }
    
    // Component-level lazy loading for modals
    const UserModal = lazy(() => 
      import('./components/UserModal').then(module => ({
        default: module.UserModal
      }))
    );
    
    function UserList() {
      const [showModal, setShowModal] = useState(false);
      
      return (
        <div>
          <button onClick={() => setShowModal(true)}>
            Open User Modal
          </button>
          {showModal && (
            <Suspense fallback={<div>Loading modal...</div>}>
              <UserModal onClose={() => setShowModal(false)} />
            </Suspense>
          )}
        </div>
      );
    }

    Advanced Hooks Patterns

    7. Custom Hooks for Reusable Logic

    Expected Creation:
    Ability to create custom hooks that abstract complex logic.

    javascript
    // Custom hook for form handling with validation
    function useForm(initialValues, validate, onSubmit) {
      const [values, setValues] = useState(initialValues);
      const [errors, setErrors] = useState({});
      const [touched, setTouched] = useState({});
      const [isSubmitting, setIsSubmitting] = useState(false);
      
      // Debounced validation
      useEffect(() => {
        const timer = setTimeout(() => {
          if (Object.keys(touched).length > 0) {
            const validationErrors = validate(values);
            setErrors(validationErrors);
          }
        }, 300);
        
        return () => clearTimeout(timer);
      }, [values, touched, validate]);
      
      const handleChange = (e) => {
        const { name, value, type, checked } = e.target;
        setValues(prev => ({
          ...prev,
          [name]: type === 'checkbox' ? checked : value
        }));
      };
      
      const handleBlur = (e) => {
        const { name } = e.target;
        setTouched(prev => ({
          ...prev,
          [name]: true
        }));
      };
      
      const handleSubmit = async (e) => {
        e.preventDefault();
        setIsSubmitting(true);
        
        // Mark all fields as touched
        const allTouched = Object.keys(values).reduce((acc, key) => {
          acc[key] = true;
          return acc;
        }, {});
        setTouched(allTouched);
        
        const validationErrors = validate(values);
        setErrors(validationErrors);
        
        if (Object.keys(validationErrors).length === 0) {
          await onSubmit(values);
        }
        
        setIsSubmitting(false);
      };
      
      const resetForm = () => {
        setValues(initialValues);
        setErrors({});
        setTouched({});
      };
      
      return {
        values,
        errors,
        touched,
        isSubmitting,
        handleChange,
        handleBlur,
        handleSubmit,
        resetForm,
        setValues
      };
    }
    
    // Usage example
    function UserRegistrationForm() {
      const validate = (values) => {
        const errors = {};
        if (!values.email) {
          errors.email = 'Email is required';
        } else if (!/\S+@\S+\.\S+/.test(values.email)) {
          errors.email = 'Email is invalid';
        }
        if (!values.password) {
          errors.password = 'Password is required';
        } else if (values.password.length < 8) {
          errors.password = 'Password must be at least 8 characters';
        }
        return errors;
      };
      
      const handleSubmit = async (values) => {
        // API call to register user
        console.log('Submitting:', values);
      };
      
      const form = useForm(
        { email: '', password: '' },
        validate,
        handleSubmit
      );
      
      return (
        <form onSubmit={form.handleSubmit}>
          <div>
            <input
              type="email"
              name="email"
              value={form.values.email}
              onChange={form.handleChange}
              onBlur={form.handleBlur}
              placeholder="Email"
            />
            {form.touched.email && form.errors.email && (
              <span style={{ color: 'red' }}>{form.errors.email}</span>
            )}
          </div>
          <div>
            <input
              type="password"
              name="password"
              value={form.values.password}
              onChange={form.handleChange}
              onBlur={form.handleBlur}
              placeholder="Password"
            />
            {form.touched.password && form.errors.password && (
              <span style={{ color: 'red' }}>{form.errors.password}</span>
            )}
          </div>
          <button type="submit" disabled={form.isSubmitting}>
            {form.isSubmitting ? 'Registering...' : 'Register'}
          </button>
        </form>
      );
    }

    8. Advanced useEffect Patterns and Cleanup

    Expected Understanding:
    Proper cleanup in useEffect and handling complex side effects.

    javascript
    // Custom hook for WebSocket connection
    function useWebSocket(url, onMessage) {
      const [socket, setSocket] = useState(null);
      const [isConnected, setIsConnected] = useState(false);
      
      useEffect(() => {
        const ws = new WebSocket(url);
        
        ws.onopen = () => {
          console.log('WebSocket connected');
          setIsConnected(true);
          setSocket(ws);
        };
        
        ws.onmessage = (event) => {
          try {
            const data = JSON.parse(event.data);
            onMessage(data);
          } catch (error) {
            console.error('Error parsing WebSocket message:', error);
          }
        };
        
        ws.onclose = () => {
          console.log('WebSocket disconnected');
          setIsConnected(false);
          setSocket(null);
        };
        
        ws.onerror = (error) => {
          console.error('WebSocket error:', error);
        };
        
        // Cleanup function
        return () => {
          if (ws.readyState === WebSocket.OPEN) {
            ws.close();
          }
        };
      }, [url, onMessage]);
      
      const sendMessage = useCallback((message) => {
        if (socket && socket.readyState === WebSocket.OPEN) {
          socket.send(JSON.stringify(message));
        } else {
          console.error('WebSocket is not connected');
        }
      }, [socket]);
      
      return { isConnected, sendMessage };
    }
    
    // Custom hook for intersection observer (infinite scroll)
    function useInfiniteScroll(ref, callback, options = {}) {
      const [isIntersecting, setIsIntersecting] = useState(false);
      
      useEffect(() => {
        const observer = new IntersectionObserver(([entry]) => {
          setIsIntersecting(entry.isIntersecting);
          if (entry.isIntersecting) {
            callback();
          }
        }, {
          root: null,
          rootMargin: '0px',
          threshold: 0.1,
          ...options
        });
        
        const currentRef = ref.current;
        if (currentRef) {
          observer.observe(currentRef);
        }
        
        return () => {
          if (currentRef) {
            observer.unobserve(currentRef);
          }
        };
      }, [ref, callback, options]);
      
      return isIntersecting;
    }
    
    // Usage example
    function InfiniteScrollList() {
      const [items, setItems] = useState([]);
      const [page, setPage] = useState(1);
      const [loading, setLoading] = useState(false);
      const loaderRef = useRef(null);
      
      const loadMore = useCallback(async () => {
        if (loading) return;
        
        setLoading(true);
        try {
          const response = await fetch(`/api/items?page=${page}`);
          const newItems = await response.json();
          setItems(prev => [...prev, ...newItems]);
          setPage(prev => prev + 1);
        } catch (error) {
          console.error('Error loading items:', error);
        } finally {
          setLoading(false);
        }
      }, [page, loading]);
      
      useInfiniteScroll(loaderRef, loadMore);
      
      return (
        <div>
          {items.map(item => (
            <div key={item.id}>{item.name}</div>
          ))}
          <div ref={loaderRef}>
            {loading && <div>Loading more items...</div>}
          </div>
        </div>
      );
    }

    Testing React Applications

    9. Testing Strategies and Tools

    Expected Knowledge:
    Understanding of testing pyramid and ability to write meaningful tests.

    javascript
    // Component test with React Testing Library
    import React from 'react';
    import { render, screen, fireEvent, waitFor } from '@testing-library/react';
    import userEvent from '@testing-library/user-event';
    import { ThemeProvider } from './ThemeContext';
    import ThemedButton from './ThemedButton';
    
    describe('ThemedButton', () => {
      test('renders with light theme by default', () => {
        render(
          <ThemeProvider>
            <ThemedButton />
          </ThemeProvider>
        );
        
        const button = screen.getByRole('button', { name: /toggle theme/i });
        expect(button).toHaveStyle('background-color: #fff');
      });
      
      test('toggles theme when clicked', async () => {
        render(
          <ThemeProvider>
            <ThemedButton />
          </ThemeProvider>
        );
        
        const button = screen.getByRole('button', { name: /toggle theme/i });
        
        // Initial state
        expect(button).toHaveStyle('background-color: #fff');
        
        // Click to toggle
        fireEvent.click(button);
        
        // Wait for state update
        await waitFor(() => {
          expect(button).toHaveStyle('background-color: #333');
        });
        
        // Click again to toggle back
        fireEvent.click(button);
        
        await waitFor(() => {
          expect(button).toHaveStyle('background-color: #fff');
        });
      });
      
      test('handles user typing interactions', async () => {
        const user = userEvent.setup();
        const handleSubmit = jest.fn();
        
        render(<LoginForm onSubmit={handleSubmit} />);
        
        const emailInput = screen.getByLabelText(/email/i);
        const passwordInput = screen.getByLabelText(/password/i);
        const submitButton = screen.getByRole('button', { name: /login/i });
        
        // Simulate user typing
        await user.type(emailInput, 'test@example.com');
        await user.type(passwordInput, 'password123');
        
        expect(emailInput).toHaveValue('test@example.com');
        expect(passwordInput).toHaveValue('password123');
        
        // Simulate form submission
        await user.click(submitButton);
        
        expect(handleSubmit).toHaveBeenCalledWith({
          email: 'test@example.com',
          password: 'password123'
        });
      });
    });
    
    // Custom hook test
    import { renderHook, act } from '@testing-library/react-hooks';
    import { useForm } from './useForm';
    
    describe('useForm', () => {
      test('handles form state changes', () => {
        const { result } = renderHook(() => 
          useForm(
            { email: '', password: '' },
            () => ({}),
            jest.fn()
          )
        );
        
        // Test initial state
        expect(result.current.values.email).toBe('');
        expect(result.current.values.password).toBe('');
        
        // Test handleChange
        act(() => {
          result.current.handleChange({
            target: { name: 'email', value: 'test@example.com' }
          });
        });
        
        expect(result.current.values.email).toBe('test@example.com');
      });
    });

    Architecture and Design Patterns

    10. Component Composition vs Inheritance

    Expected Understanding:
    Knowledge of React's composition model and when to use different patterns.

    javascript
    // Compound Components Pattern
    const Tabs = ({ children, defaultActiveTab }) => {
      const [activeTab, setActiveTab] = useState(defaultActiveTab);
      
      const contextValue = useMemo(() => ({
        activeTab,
        setActiveTab
      }), [activeTab]);
      
      return (
        <TabsContext.Provider value={contextValue}>
          <div className="tabs">{children}</div>
        </TabsContext.Provider>
      );
    };
    
    const TabList = ({ children }) => {
      return <div className="tab-list">{children}</div>;
    };
    
    const Tab = ({ children, tabId }) => {
      const { activeTab, setActiveTab } = useContext(TabsContext);
      
      return (
        <button
          className={`tab ${activeTab === tabId ? 'active' : ''}`}
          onClick={() => setActiveTab(tabId)}
        >
          {children}
        </button>
      );
    };
    
    const TabPanels = ({ children }) => {
      return <div className="tab-panels">{children}</div>;
    };
    
    const TabPanel = ({ children, tabId }) => {
      const { activeTab } = useContext(TabsContext);
      
      if (activeTab !== tabId) return null;
      
      return <div className="tab-panel">{children}</div>;
    };
    
    // Usage
    function App() {
      return (
        <Tabs defaultActiveTab="profile">
          <TabList>
            <Tab tabId="profile">Profile</Tab>
            <Tab tabId="settings">Settings</Tab>
            <Tab tabId="messages">Messages</Tab>
          </TabList>
          <TabPanels>
            <TabPanel tabId="profile">
              <ProfileContent />
            </TabPanel>
            <TabPanel tabId="settings">
              <SettingsContent />
            </TabPanel>
            <TabPanel tabId="messages">
              <MessagesContent />
            </TabPanel>
          </TabPanels>
        </Tabs>
      );
    }
    
    // Render Props Pattern
    class MouseTracker extends React.Component {
      state = { x: 0, y: 0 };
      
      handleMouseMove = (event) => {
        this.setState({
          x: event.clientX,
          y: event.clientY
        });
      };
      
      render() {
        return (
          <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
            {this.props.render(this.state)}
          </div>
        );
      }
    }
    
    // Usage
    function App() {
      return (
        <MouseTracker
          render={({ x, y }) => (
            <div>
              <h1>Move the mouse around!</h1>
              <p>The current mouse position is ({x}, {y})</p>
            </div>
          )}
        />
      );
    }

    Error Boundaries and Error Handling

    11. Implementing and Using Error Boundaries

    Expected Implementation:
    Ability to create error boundaries and handle React errors gracefully.

    javascript
    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { 
          hasError: false, 
          error: null, 
          errorInfo: null,
          retryCount: 0
        };
      }
      
      static getDerivedStateFromError(error) {
        return { hasError: true };
      }
      
      componentDidCatch(error, errorInfo) {
        console.error('Error caught by boundary:', error, errorInfo);
        
        // Log error to monitoring service
        this.logErrorToService(error, errorInfo);
        
        this.setState({ 
          error, 
          errorInfo,
          retryCount: this.state.retryCount + 1
        });
      }
      
      logErrorToService = (error, errorInfo) => {
        // Implementation for error logging service
        if (window.errorLoggingService) {
          window.errorLoggingService.log({
            error: error.toString(),
            stack: error.stack,
            componentStack: errorInfo.componentStack,
            url: window.location.href,
            timestamp: new Date().toISOString()
          });
        }
      };
      
      handleRetry = () => {
        this.setState({ 
          hasError: false, 
          error: null, 
          errorInfo: null 
        });
      };
      
      handleReset = () => {
        this.setState({ 
          hasError: false, 
          error: null, 
          errorInfo: null,
          retryCount: 0 
        });
      };
      
      render() {
        if (this.state.hasError) {
          // Custom fallback UI
          return (
            <div className="error-boundary">
              <h2>Something went wrong</h2>
              <details style={{ whiteSpace: 'pre-wrap' }}>
                <summary>Error Details</summary>
                {this.state.error && this.state.error.toString()}
                <br />
                {this.state.errorInfo && this.state.errorInfo.componentStack}
              </details>
              
              <div className="error-actions">
                <button onClick={this.handleRetry}>
                  {this.state.retryCount < 3 ? 'Try Again' : 'Retry (Limited)'}
                </button>
                <button onClick={this.handleReset}>
                  Reset Component
                </button>
                <button onClick={() => window.location.reload()}>
                  Reload Page
                </button>
              </div>
              
              {this.state.retryCount >= 3 && (
                <div className="error-warning">
                  <p>Multiple retries failed. Please contact support if the problem persists.</p>
                </div>
              )}
            </div>
          );
        }
        
        return this.props.children;
      }
    }
    
    // Usage with different fallback strategies
    function App() {
      return (
        <ErrorBoundary>
          <Suspense fallback={<LoadingSpinner />}>
            <Router>
              <Switch>
                <Route exact path="/" component={Home} />
                <Route path="/dashboard">
                  <ErrorBoundary 
                    fallback={<DashboardErrorFallback />}
                  >
                    <Dashboard />
                  </ErrorBoundary>
                </Route>
                <Route path="/profile">
                  <ErrorBoundary 
                    onError={(error) => {
                      // Custom error handling
                      if (error instanceof AuthenticationError) {
                        window.location.href = '/login';
                      }
                    }}
                  >
                    <Profile />
                  </ErrorBoundary>
                </Route>
              </Switch>
            </Router>
          </Suspense>
        </ErrorBoundary>
      );
    }

    Real-World Problem Solving

    12. Interview Scenario: Building a Real-Time Dashboard

    Problem Statement:
    "Design a real-time dashboard that displays live data updates, supports filtering, and maintains performance with frequent updates."

    Expected Solution Approach:

    javascript
    // Real-time dashboard implementation
    function RealTimeDashboard() {
      const [metrics, setMetrics] = useState({});
      const [filters, setFilters] = useState({
        timeRange: '1h',
        metricType: 'all',
        region: 'all'
      });
      const [isPaused, setIsPaused] = useState(false);
      
      // WebSocket connection for real-time data
      const { isConnected, sendMessage } = useWebSocket(
        'wss://api.example.com/metrics',
        handleWebSocketMessage
      );
      
      // Throttle updates to prevent excessive re-renders
      const throttledSetMetrics = useMemo(
        () => throttle(setMetrics, 1000),
        []
      );
      
      function handleWebSocketMessage(data) {
        if (isPaused) return;
        
        throttledSetMetrics(prev => ({
          ...prev,
          [data.metricId]: {
            ...prev[data.metricId],
            value: data.value,
            timestamp: data.timestamp,
            history: [
              ...(prev[data.metricId]?.history || []).slice(-99),
              { value: data.value, timestamp: data.timestamp }
            ]
          }
        }));
      }
      
      // Filter metrics based on current filters
      const filteredMetrics = useMemo(() => {
        return Object.entries(metrics).filter(([id, metric]) => {
          if (filters.metricType !== 'all' && metric.type !== filters.metricType) {
            return false;
          }
          if (filters.region !== 'all' && metric.region !== filters.region) {
            return false;
          }
          return true;
        });
      }, [metrics, filters]);
      
      // Aggregate data for summary
      const summary = useMemo(() => {
        return filteredMetrics.reduce((acc, [id, metric]) => {
          acc.total += metric.value;
          acc.count++;
          acc.average = acc.total / acc.count;
          return acc;
        }, { total: 0, count: 0, average: 0 });
      }, [filteredMetrics]);
      
      // Virtualized list for performance
      const rowVirtualizer = useVirtualizer({
        count: filteredMetrics.length,
        getScrollElement: () => listRef.current,
        estimateSize: () => 100,
        overscan: 5
      });
      
      return (
        <div className="dashboard">
          <DashboardHeader 
            isConnected={isConnected}
            isPaused={isPaused}
            onPauseToggle={() => setIsPaused(!isPaused)}
            summary={summary}
          />
          
          <DashboardFilters 
            filters={filters}
            onFilterChange={setFilters}
          />
          
          <div 
            ref={listRef}
            style={{ height: '600px', overflow: 'auto' }}
          >
            <div style={{ height: `${rowVirtualizer.getTotalSize()}px` }}>
              {rowVirtualizer.getVirtualItems().map(virtualItem => {
                const [id, metric] = filteredMetrics[virtualItem.index];
                return (
                  <div
                    key={id}
                    style={{
                      position: 'absolute',
                      top: 0,
                      left: 0,
                      width: '100%',
                      height: `${virtualItem.size}px`,
                      transform: `translateY(${virtualItem.start}px)`
                    }}
                  >
                    <MetricCard 
                      metric={metric}
                      onSelect={() => {/* Handle selection */}}
                    />
                  </div>
                );
              })}
            </div>
          </div>
          
          <DashboardFooter 
            lastUpdated={new Date()}
            totalMetrics={filteredMetrics.length}
          />
        </div>
      );
    }

    Conclusion: Evaluating Mid-Level React Developers

    When interviewing mid-level React developers, look for:

    1. Deep Understanding of Core Concepts: They should explain Virtual DOM, reconciliation, and lifecycle methods in detail.

    2. Practical Experience with Hooks: Ability to create custom hooks and understand dependency arrays.

    3. Performance Awareness: Knowledge of memoization, code splitting, and optimization techniques.

    4. State Management Proficiency: Understanding when to use different state management solutions.

    5. Testing Competence: Ability to write meaningful tests and understand testing strategies.

    6. Problem-Solving Skills: Can architect solutions for complex requirements.

    7. Error Handling: Implements proper error boundaries and graceful degradation.

    8. Code Organization: Writes clean, maintainable code with proper separation of concerns.

    Remember that mid-level developers should not only solve problems but also understand why their solutions work and be able to communicate their thought process effectively. They should balance speed with quality and be able to work independently while knowing when to seek guidance.

    This guide provides a comprehensive framework for assessing mid-level React developers, but always tailor your interview to your specific needs and team dynamics. The best developers are those who not only have technical skills but also fit well with your team culture and can grow with your organization.


#career

Ready to Build Your Resume?

Create a professional resume that stands out to recruiters with our AI-powered builder.

50+ Essential React Interview Questions for Freshers (2026) | Hirecta Interview Prep | Hirecta