Posted in

Top 30 React Interview Questions and Answers for All Experience Levels

Prepare for Your React Interview: Basic to Advanced Questions

This comprehensive guide covers 30 essential React interview questions arranged by difficulty level – from basic concepts for freshers to advanced scenarios for experienced developers. Each question includes clear, practical answers with code examples to help you prepare effectively.

Basic React Interview Questions (Freshers)

1. What is React and how does it work?

React is a JavaScript library for building user interfaces by creating reusable components. It works through a Virtual DOM that tracks changes and updates only the necessary parts of the real DOM using a reconciliation process.[1]

2. What is JSX and how is it different from HTML?

JSX is a syntax extension for JavaScript that looks like HTML but gets transpiled to React.createElement() calls. Unlike HTML, JSX allows JavaScript expressions inside curly braces {} and must have one parent element.[1]

3. What is the difference between Element and Component in React?

Elements are plain JavaScript objects describing what to render, while Components are reusable functions or classes that return elements. Components accept props and manage state.[1]

4. What are functional components vs class components?

// Functional Component
const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
};

// Class Component  
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Functional components are simpler, stateless by default, and use hooks. Class components use lifecycle methods and this.state.[1]

5. What is the useState hook and how do you use it?

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

useState manages local component state, returning current state and a setter function.[1]

6. Explain props in React with an example.

// Parent Component
function App() {
  return <Profile name="John" age={25} />;
}

// Child Component
function Profile(props) {
  return <p>{props.name} is {props.age} years old</p>;
}

Props pass data from parent to child components unidirectionally.[1]

7. What is the Virtual DOM and why is it important?

Virtual DOM is a lightweight JavaScript representation of the real DOM. React compares new Virtual DOM with previous versions (diffing) and updates only changed elements, improving performance.[1][2]

Intermediate React Interview Questions (1-3 Years Experience)

8. What is useEffect hook and when does it run?

import { useEffect, useState } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetchData();
  }, []); // Empty dependency = runs once
  
  useEffect(() => {
    document.title = `Count: ${data?.length}`;
  }, [data]); // Runs when data changes
  
  return <div>Data loaded</div>;
}

useEffect handles side effects like API calls, subscriptions. It runs after render; dependency array controls execution timing.[1][2]

9. Explain React lifecycle methods in class components.

Key lifecycle methods include:

  • componentDidMount(): After component mounts to DOM
  • shouldComponentUpdate(): Decide if component should re-render
  • componentDidUpdate(): After component updates
  • componentWillUnmount(): Before component unmounts (cleanup)

[1][4]

10. What are React Hooks and list built-in hooks?

React Hooks let functional components use state and lifecycle features. Built-in hooks: useState, useEffect, useContext, useReducer, useCallback, useMemo, useRef.[1][4]

11. How do you prevent unnecessary re-renders in React?

import React, { memo, useCallback } from 'react';

const Child = memo(({ onClick }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Click</button>;
});

function Parent() {
  const handleClick = useCallback(() => {
    console.log('Clicked');
  }, []);
  
  return <Child onClick={handleClick} />;
}

Use React.memo, useCallback, useMemo, and proper dependency arrays.[1]

12. What is the Context API and when to use it?

const ThemeContext = createContext();

function App() {
  const [theme, setTheme] = useState('light');
  
  return (
    <ThemeContext.Provider value={{theme, setTheme}}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  const {theme} = useContext(ThemeContext);
  return <div className={theme}>Toolbar</div>;
}

Context API shares data across component tree without prop drilling. Ideal for theme, auth, language settings.[1][2]

13. Explain controlled vs uncontrolled components.

// Controlled Component
function ControlledInput() {
  const [value, setValue] = useState('');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}

// Uncontrolled Component
function UncontrolledInput() {
  const inputRef = useRef();
  return (
    <>
      <input ref={inputRef} />
      <button onClick={() => alert(inputRef.current.value)}>Get Value</button>
    </>
  );
}

Controlled components use React state for input value. Uncontrolled use DOM refs.[1]

Advanced React Interview Questions (3-6 Years Experience)

14. What is React.memo and how does it work?

const ExpensiveComponent = React.memo(function MyComponent({ data }) {
  // Component logic
  return <div>{data.name}</div>;
}, (prevProps, nextProps) => {
  // Custom comparison logic
  return prevProps.data.id === nextProps.data.id;
});

React.memo prevents re-renders if props haven’t changed. Accepts custom comparison function.[1]

15. Explain useCallback vs useMemo with examples.

function Parent() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');
  
  // useCallback: Memoizes functions
  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []);
  
  // useMemo: Memoizes values
  const expensiveValue = useMemo(() => {
    return name.split('').reverse().join('');
  }, [name]);
  
  return <><button onClick={handleClick}>Count</button></>;
}

useCallback memoizes functions, useMemo memoizes computed values.[1]

16. How do you implement error boundaries in React?

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  componentDidCatch(error, errorInfo) {
    console.error('Error:', error, errorInfo);
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

// Usage
<ErrorBoundary>
  <BuggyComponent />
</ErrorBoundary>

Error boundaries catch JavaScript errors in child component trees.[1]

17. What is the purpose of useReducer hook?

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
    </>
  );
}

useReducer manages complex state logic, similar to Redux.[1][4]

18. Implement custom hook for localStorage persistence.

function useLocalStorage(key, initialValue) {
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      return initialValue;
    }
  });
  
  const setValue = useCallback((value) => {
    try {
      setStoredValue(value);
      window.localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(error);
    }
  }, [key]);
  
  return [storedValue, setValue];
}

Custom hooks encapsulate reusable stateful logic.[1][3]

Scenario-Based React Interview Questions

19. At Atlassian, how would you fetch and display API data with loading states?

function ProductList() {
  const [products, setProducts] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    const fetchProducts = async () => {
      try {
        setLoading(true);
        const response = await fetch('/api/products');
        const data = await response.json();
        setProducts(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };
    fetchProducts();
  }, []);
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>{product.name}</li>
      ))}
    </ul>
  );
}

[2]

20. Implement a search input with debouncing for Swiggy’s product search.

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);
  
  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);
    
    return () => clearTimeout(handler);
  }, [value, delay]);
  
  return debouncedValue;
}

function Search() {
  const [query, setQuery] = useState('');
  const debouncedQuery = useDebounce(query, 300);
  
  useEffect(() => {
    if (debouncedQuery) {
      // API call
      searchProducts(debouncedQuery);
    }
  }, [debouncedQuery]);
  
  return <input 
    value={query} 
    onChange={(e) => setQuery(e.target.value)}
    placeholder="Search products..." 
  />;
}

Debouncing prevents excessive API calls during typing.[5]

21. How would Adobe handle form validation with multiple fields?

function useFormValidation(initialState) {
  const [values, setValues] = useState(initialState);
  const [errors, setErrors] = useState({});
  
  const validate = (name, value) => {
    if (!value.trim()) {
      return `${name} is required`;
    }
    return '';
  };
  
  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues(prev => ({ ...prev, [name]: value }));
    
    const error = validate(name, value);
    setErrors(prev => ({ ...prev, [name]: error }));
  };
  
  return { values, errors, handleChange };
}

Custom validation hook manages form state and errors.[3]

22. Create a counter with max limit for Paytm checkout.

function QuantitySelector({ max = 10 }) {
  const [quantity, setQuantity] = useState(1);
  
  const increment = () => {
    if (quantity < max) {
      setQuantity(quantity + 1);
    }
  };
  
  const decrement = () => {
    if (quantity > 1) {
      setQuantity(quantity - 1);
    }
  };
  
  return (
    <div>
      <button onClick={decrement} disabled={quantity === 1}>-</button>
      <span>{quantity}</span>
      <button onClick={increment} disabled={quantity === max}>+</button>
    </div>
  );
}

23. Implement infinite scroll for Flipkart product listing.

function InfiniteScrollList() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [loading, setLoading] = useState(false);
  
  const observer = useRef();
  const lastItemRef = useCallback(node => {
    if (loading) return;
    
    if (observer.current) observer.current.disconnect();
    observer.current = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting) {
        setPage(prev => prev + 1);
      }
    });
    
    if (node) observer.current.observe(node);
  }, [loading]);
  
  useEffect(() => {
    fetchMoreData(page);
  }, [page]);
  
  return (
    <ul>
      {items.map((item, index) => {
        if (items.length === index + 1) {
          return <li key={item.id} ref={lastItemRef}>{item.name}</li>;
        }
        return <li key={item.id}>{item.name}</li>;
      })}
    </ul>
  );
}

24. How to optimize large lists at Salesforce?

function VirtualizedList({ items, height, itemHeight }) {
  const [scrollTop, setScrollTop] = useState(0);
  
  const startIndex = Math.floor(scrollTop / itemHeight);
  const visibleCount = Math.ceil(height / itemHeight);
  const endIndex = startIndex + visibleCount;
  
  const visibleItems = items.slice(startIndex, endIndex);
  
  return (
    <div 
      style={{ height, overflow: 'auto' }}
      onScroll={(e) => setScrollTop(e.target.scrollTop)}
    >
      <div style={{ height: items.length * itemHeight, position: 'relative' }}>
        {visibleItems.map(item => (
          <div 
            key={item.id}
            style={{
              position: 'absolute',
              top: (items.indexOf(item) * itemHeight) + 'px',
              height: itemHeight
            }}
          >
            {item.name}
          </div>
        ))}
      </div>
    </div>
  );
}

Virtualization renders only visible items for performance.[1]

25. Create a toast notification system for Zoho.

function useToast() {
  const [toasts, setToasts] = useState([]);
  
  const addToast = (message, type = 'info') => {
    const id = Date.now();
    setToasts(prev => [...prev, { id, message, type }]);
    
    setTimeout(() => {
      setToasts(prev => prev.filter(toast => toast.id !== id));
    }, 3000);
  };
  
  return { toasts, addToast };
}

function ToastContainer({ toasts }) {
  return (
    <div className="toast-container">
      {toasts.map(toast => (
        <div key={toast.id} className={`toast toast-${toast.type}`}>
          {toast.message}
        </div>
      ))}
    </div>
  );
}

26. Implement drag and drop reordering for SAP dashboard.

function DraggableList({ items, onReorder }) {
  const [dragItem, setDragItem] = useState(null);
  
  const handleDragStart = (e, index) => {
    setDragItem(index);
    e.dataTransfer.effectAllowed = 'move';
  };
  
  const handleDrop = (e, dropIndex) => {
    e.preventDefault();
    const newItems = [...items];
    const [draggedItem] = newItems.splice(dragItem, 1);
    newItems.splice(dropIndex, 0, draggedItem);
    onReorder(newItems);
  };
  
  return items.map((item, index) => (
    <div
      key={item.id}
      draggable
      onDragStart={(e) => handleDragStart(e, index)}
      onDragOver={(e) => e.preventDefault()}
      onDrop={(e) => handleDrop(e, index)}
      className="draggable-item"
    >
      {item.name}
    </div>
  ));
}

27. Memoize expensive calculations at Oracle reports.

function ReportTable({ rawData }) {
  const summary = useMemo(() => {
    return rawData.reduce((acc, item) => {
      acc.total += item.amount;
      acc.count += 1;
      acc.avg = acc.total / acc.count;
      return acc;
    }, { total: 0, count: 0, avg: 0 });
  }, [rawData]);
  
  const sortedData = useMemo(() => {
    return [...rawData].sort((a, b) => b.amount - a.amount);
  }, [rawData]);
  
  return (
    <div>
      <p>Total: {summary.total} | Avg: {summary.avg.toFixed(2)}</p>
      <table>{sortedData.map(item => <tr key={item.id}><td>{item.amount}</td></tr>)}</table>
    </div>
  );
}

28. Handle concurrent API calls with race condition prevention.

function useApi(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  
  const fetchData = useCallback(async (fresh = false) => {
    if (loading && !fresh) return;
    
    setLoading(true);
    try {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
    } finally {
      setLoading(false);
    }
  }, [url, loading]);
  
  return { data, loading, refetch: fetchData };
}

29. Create a compound component pattern for tabs at Amazon.

const TabContext = createContext();

function Tabs({ children, defaultIndex = 0 }) {
  const [activeIndex, setActiveIndex] = useState(defaultIndex);
  return (
    <TabContext.Provider value={{ activeIndex, setActiveIndex }}>
      <div className="tabs">{children}</div>
    </TabContext.Provider>
  );
}

function TabList({ children }) {
  return <div role="tablist">{children}</div>;
}

function Tab({ children, index }) {
  const { activeIndex, setActiveIndex } = useContext(TabContext);
  return (
    <button 
      role="tab"
      aria-selected={activeIndex === index}
      onClick={() => setActiveIndex(index)}
    >
      {children}
    </button>
  );
}

function TabPanel({ children, index }) {
  const { activeIndex } = useContext(TabContext);
  return activeIndex === index ? <div role="tabpanel">{children}</div> : null;
}

// Usage: <Tabs><TabList><Tab index={0}>Tab 1</Tab></TabList><TabPanel index={0}>Content 1</TabPanel></Tabs>

30. Implement React Suspense with lazy loading for code splitting.

const LazyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading component...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

// webpack automatically code-splits into separate chunks

Suspense shows fallback UI while lazy-loaded components fetch.[1][3]

Leave a Reply

Your email address will not be published. Required fields are marked *