React

React Interview Questions and Answers

Master React interviews with questions on hooks, components, state management, performance optimization, and React 18 features.

šŸ“‹ Jump to Question

1. What is React and why should we use it?

React is a JavaScript library created by Facebook for building interactive user interfaces. Think of it like a smart way to build websites where only the parts that need to change actually update, without refreshing the whole page.

Why use React?

  • Component-based: Build your UI like LEGO blocks that you can reuse anywhere
  • Fast updates: Only updates what changed, not the whole page
  • Great for teams: Clear structure makes it easier to work together
  • Huge community: Lots of help available and many companies use it
  • Works everywhere: Can make websites, mobile apps (React Native), and desktop apps
// A basic React component
function WelcomeMessage() {
  return <h1>Hello, welcome to our website!</h1>;
}

2. What is the Virtual DOM?

Imagine you're painting a picture and want to change just one small part. Instead of repainting everything, you only paint over that small area. That's what React does with Virtual DOM.

How it works:

  1. React keeps a copy of your page in memory (Virtual DOM)
  2. When something changes, React creates a new Virtual DOM
  3. React compares the old and new versions (like "spot the difference")
  4. Only the changed parts update on the actual webpage
  5. This makes websites much faster

React's Virtual DOM is a JavaScript object that represents what your page looks like. When state changes, React creates a new object, compares it with the old one using a "diffing algorithm," and then efficiently updates only what changed in the real browser DOM.

3. What are Components?

Components are like building blocks for your website. Each component is a self-contained piece of UI with its own logic and appearance.

Types of components:

  • Functional Components: Simple functions that return what to display
  • Class Components: More feature-rich, use classes (older style)
  • Presentational Components: Just show things (like a button)
  • Container Components: Handle data and logic

Think of it like this: Your website = House Each room = Component (Kitchen, Bedroom, Living Room) Each component handles its own stuff

// A simple component
function UserProfile(props) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>{props.bio}</p>
    </div>
  );
}

4. What is JSX?

JSX looks like HTML but it's actually JavaScript. It's React's special language for describing what components should look like.

Key things about JSX:

  • Looks like HTML but works inside JavaScript
  • Must have a single parent element (wrap multiple elements in a div or fragment)
  • Use className instead of class (because "class" is a JavaScript keyword)
  • Can embed JavaScript expressions with {}

Simple example: <h1>Hello {userName}</h1> mixes HTML-like tags with JavaScript variables.

// Correct JSX
return (
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
);

// Wrong JSX (multiple root elements)
return (
  <h1>Title</h1>
  <p>Content</p>  // Error!
);

5. What are Props?

Props (short for properties) are how you pass data from a parent component to a child component. They're read-only - the child can't change them.

Analogy: Props are like parameters you give to a function. If you have a Greeting component, you might pass it a name prop: <Greeting name="Sarah" />

Important:

  • Props flow down (parent → child)
  • Props are immutable (can't be changed by child)
  • Use props to make components reusable
// Parent component
function App() {
  return <WelcomeMessage name="Alex" />;
}

// Child component receiving props
function WelcomeMessage(props) {
  return <h1>Hello, {props.name}!</h1>;
}

State and Lifecycle

6. What is State?

State is data that can change over time within a component. Unlike props (which come from outside), state is managed internally by the component.

Think of state as:

  • A component's memory
  • Data that changes and causes re-renders
  • Local to the component (unless shared)

Example use cases:

  • Form input values
  • Toggle switches (on/off)
  • Counter values
  • Loading status (loading/loaded)
function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

7. Props vs State - What's the difference?

This is a very common interview question!

Props (Properties):

  • Come from parent component
  • Are read-only (child can't modify)
  • Like function parameters
  • Used to pass data down

State:

  • Managed within component
  • Can be modified using setState
  • Like component's memory
  • Changes cause re-render

Analogy: If a component is a restaurant table:

  • Props = The menu you're given (can't change it)
  • State = What you've ordered so far (can add/remove)

| | Props | State | |---|---|---| | Source | Parent component | Component itself | | Can change? | No (immutable) | Yes (mutable) | | Purpose | Pass data down | Track changes | | Changes cause re-render? | Yes (if parent changes) | Yes |

8. What are React Lifecycle Methods?

Lifecycle methods are like different stages in a component's life: birth, updates, and death. They let you run code at specific times.

Main lifecycle stages:

  1. Mounting - Component is being created and inserted into DOM
  2. Updating - Component is re-rendering due to props/state changes
  3. Unmounting - Component is being removed from DOM

Common lifecycle methods:

  • componentDidMount() - Runs after component appears on screen (good for API calls)
  • componentDidUpdate() - Runs after component updates
  • componentWillUnmount() - Runs before component disappears (cleanup)
1. constructor() - Component is being created
2. render() - Component draws itself
3. componentDidMount() - Component is now on screen
4. componentDidUpdate() - Component updated
5. componentWillUnmount() - Component about to disappear

React Hooks (Modern React)

9. What are React Hooks?

Hooks are functions that let you "hook into" React features from functional components. Before hooks, you needed class components for state and lifecycle.

Why hooks were introduced:

  • Simplify complex components
  • Reuse stateful logic between components
  • Make code easier to understand and test
  • Reduce the need for class components

Most important hooks:

  • useState - Add state to functional components
  • useEffect - Handle side effects (API calls, subscriptions)
  • useContext - Access context without nesting
  • useRef - Reference DOM elements or persistent values
import { useState, useEffect } from 'react';

function UserProfile() {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // Fetch user data when component mounts
    fetchUser().then(data => setUser(data));
  }, []);
  
  if (!user) return <div>Loading...</div>;
  return <div>Hello, {user.name}</div>;
}

10. Explain useState Hook

useState is the hook that lets you add state to functional components.

How it works:

  1. Call useState(initialValue) - returns [currentValue, setterFunction]
  2. Use the setter function to update state
  3. Component re-renders with new state

Simple analogy: useState is like having a variable that, when changed, automatically updates your UI.

function ToggleSwitch() {
  const [isOn, setIsOn] = useState(false);
  
  return (
    <div>
      <p>Switch is {isOn ? 'ON' : 'OFF'}</p>
      <button onClick={() => setIsOn(!isOn)}>
        Toggle
      </button>
    </div>
  );
}

11. Explain useEffect Hook

useEffect handles side effects - things that happen as a "side effect" of rendering.

What are side effects?

  • Fetching data from API
  • Setting up subscriptions
  • Manually changing the DOM
  • Setting timers

How useEffect works:

  • Runs after component renders
  • Can run once, or when dependencies change
  • Can return cleanup function
// Run once (on mount)
useEffect(() => {
  console.log('Component mounted');
}, []);

// Run when count changes
useEffect(() => {
  document.title = `Count: ${count}`;
}, [count]);

// With cleanup
useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tick');
  }, 1000);
  
  return () => clearInterval(timer); // Cleanup
}, []);

12. What is the Dependency Array in useEffect?

The dependency array (second argument to useEffect) tells React when to run your effect.

Three patterns:

  1. No array - Runs after every render (usually avoid this)
  2. Empty array [] - Runs once after initial render (like componentDidMount)
  3. Array with values [dep1, dep2] - Runs when any dependency changes (like componentDidUpdate for those values)
// 1. Run on every render (careful!)
useEffect(() => {
  // Runs after every render
});

// 2. Run once on mount
useEffect(() => {
  // Fetch initial data
}, []);

// 3. Run when userId changes
useEffect(() => {
  // Fetch user data
}, [userId]);

13. Explain useContext Hook

useContext lets you access data from React Context without passing props through every level (prop drilling).

Problem it solves: When you need to pass data deep down through many components.

How it works:

  1. Create a Context
  2. Wrap components with Provider
  3. Use useContext to access the value anywhere below
// Create context
const ThemeContext = React.createContext('light');

// Provide value
function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Header />
    </ThemeContext.Provider>
  );
}

// Use value
function Header() {
  const theme = useContext(ThemeContext);
  return <header className={theme}>Header</header>;
}

14. What are useMemo and useCallback?

These hooks optimize performance by memoizing (caching) values and functions.

useMemo - Memoizes expensive calculations useCallback - Memoizes functions so they don't get recreated

When to use them:

  • When you have expensive calculations
  • When passing callbacks to optimized child components
  • To prevent unnecessary re-renders
// Without optimization - re-calculates on every render
const sortedList = list.sort((a, b) => a - b);

// With useMemo - only re-calculates when list changes
const sortedList = useMemo(() => {
  return list.sort((a, b) => a - b);
}, [list]);

Component Communication

15. How do components communicate with each other?

Components talk to each other in several ways:

  1. Parent to Child - Using props
  2. Child to Parent - Using callback functions passed as props
  3. Sibling to Sibling - Through common parent (lifting state up)
  4. Any to Any - Using Context API or state management (Redux)

Lifting State Up: When siblings need to share data, move the state to their closest common ancestor.

// Child to parent communication
function Parent() {
  const handleChildEvent = (data) => {
    console.log('Child sent:', data);
  };
  
  return <Child onEvent={handleChildEvent} />;
}

function Child({ onEvent }) {
  return <button onClick={() => onEvent('Hello')}>Send</button>;
}

16. What is Prop Drilling?

Prop drilling happens when you pass props through multiple levels of components just to get them to a deeply nested child.

Problem: Middle components don't use the props, they just pass them along.

Solutions:

  1. Context API - Share data without passing props
  2. Component Composition - Pass components as children
  3. State Management - Redux, Zustand, etc.
// Bad: Prop drilling
<App user={user}>           // Uses user
  <Header user={user}>      // Doesn't use user, just passes
    <Navbar user={user}>    // Doesn't use user, just passes
      <Profile user={user}> // Finally uses user!
      </Profile>
    </Navbar>
  </Header>
</App>

Performance Optimization

17. How to optimize React performance?

React is fast by default, but here are ways to make it faster:

  1. React.memo() - Memoize components to prevent unnecessary re-renders
  2. useMemo/useCallback - Memoize values and functions
  3. Code Splitting - Load code only when needed
  4. Virtualize Long Lists - Only render visible items
  5. Avoid Inline Functions - In render methods
  6. Production Build - Use minified version for deployment

Golden Rule: Don't optimize prematurely. Measure first, then optimize bottlenecks.

// Memoize component
const ExpensiveComponent = React.memo(function MyComponent(props) {
  // Only re-renders if props change
  return <div>{props.value}</div>;
});

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

18. What is React.memo?

React.memo is a higher-order component that memoizes your component. If the props haven't changed, it won't re-render.

When to use it:

  • Component renders often with same props
  • Component is expensive to render
  • Props don't change frequently

When NOT to use it:

  • Component always gets new props
  • Component is cheap to render
  • You need latest props always
// Without memo - re-renders on parent re-render
function UserProfile({ user }) {
  return <div>{user.name}</div>;
}

// With memo - only re-renders if user prop changes
const UserProfile = React.memo(function({ user }) {
  return <div>{user.name}</div>;
});

Advanced Concepts

19. What are Error Boundaries?

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree and display a fallback UI instead of crashing.

What they catch:

  • Errors during rendering
  • Errors in lifecycle methods
  • Errors in constructors

What they DON'T catch:

  • Errors in event handlers (use try-catch)
  • Errors in asynchronous code
  • Errors in server-side rendering
class ErrorBoundary extends React.Component {
  state = { hasError: false };
  
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

// Usage
<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

20. What are Higher-Order Components (HOC)?

HOC is a pattern where a function takes a component and returns a new component with additional functionality.

Think of it as: Wrapping a gift. The gift (component) stays the same, but you add wrapping paper (extra features).

Common uses:

  • Adding authentication checks
  • Adding loading states
  • Adding data fetching
  • Adding styling/theming
function withLoading(WrappedComponent) {
  return function EnhancedComponent(props) {
    if (props.isLoading) {
      return <div>Loading...</div>;
    }
    return <WrappedComponent {...props} />;
  };
}

const UserProfileWithLoading = withLoading(UserProfile);

21. What are Custom Hooks?

Custom hooks let you extract component logic into reusable functions. They're like your own personal hooks!

Rules for custom hooks:

  1. Name must start with "use" (so React knows it's a hook)
  2. Can call other hooks
  3. Should be pure functions

When to create custom hooks:

  • When you use the same logic in multiple components
  • When component logic gets complex
  • To make code more readable
function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(() => {
    const stored = localStorage.getItem(key);
    return stored ? JSON.parse(stored) : initialValue;
  });
  
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);
  
  return [value, setValue];
}

// Usage in component
function Component() {
  const [name, setName] = useLocalStorage('name', 'Guest');
  return <input value={name} onChange={e => setName(e.target.value)} />;
}

State Management

22. When to use Context API vs Redux?

Context API (built into React):

  • Good for simple global state (theme, auth, language)
  • Less boilerplate
  • No middleware
  • Good for small to medium apps

Redux (external library):

  • Good for complex state with lots of updates
  • Time-travel debugging
  • Middleware support (thunk, saga)
  • Good for large apps with complex state
  • More boilerplate but more features

Rule of thumb: Start with Context API, move to Redux if you need its features.

| | Context API | Redux | |---|---|---| | Built-in | Yes | No (external) | | Learning curve | Easy | Steeper | | Boilerplate | Minimal | More | | DevTools | Basic | Excellent | | Middleware | No | Yes | | Performance | Good for small data | Optimized for large |

23. What is Redux?

Redux is a state management library that follows three principles:

  1. Single Source of Truth - Entire app state in one store
  2. State is Read-Only - Only changed by dispatching actions
  3. Changes with Pure Functions - Reducers specify how state changes

Redux Flow:

  1. Dispatch an action (like sending a message)
  2. Reducer processes the action (like a rules engine)
  3. Store updates with new state
  4. Components re-render with new state
Component → Action → Reducer → Store → Component
   ↓           ↓         ↓        ↓       ↓
 Button   "ADD_TODO"  Updates  New state  Renders
  Click              state     saved     with new
                                           data

React Router

24. What is React Router?

React Router is the standard library for adding navigation to React apps. It lets you create single-page applications with multiple "pages" without reloading.

Key concepts:

  • Routes - Map URLs to components
  • Links - Navigation between routes
  • Params - Dynamic parts of URLs (like /users/:id)
  • Nested Routes - Routes inside routes
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>
      
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/users/:id" element={<UserProfile />} />
      </Routes>
    </BrowserRouter>
  );
}

Testing

25. How to test React components?

Testing ensures your components work correctly. Common approaches:

  1. Unit Tests - Test individual components/functions
  2. Integration Tests - Test how components work together
  3. End-to-End Tests - Test complete user flows

Popular tools:

  • Jest - Testing framework (created by Facebook)
  • React Testing Library - Test components like users do
  • Cypress - End-to-end testing
// Test a button component
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';

test('button shows correct text', () => {
  render(<Button>Click me</Button>);
  expect(screen.getByText('Click me')).toBeInTheDocument();
});

test('button click works', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Click</Button>);
  
  fireEvent.click(screen.getByText('Click'));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

React 18 Features

26. What's new in React 18?

React 18 focuses on improving performance and user experience:

  1. Concurrent Features - React can work on multiple tasks at once
  2. Automatic Batching - Multiple state updates grouped together
  3. Transitions - Mark some updates as non-urgent
  4. Suspense for Data Fetching - Better loading states
  5. New Root API - ReactDOM.createRoot()

Concurrent React: Like having multiple checkout lanes instead of one - better experience when many things happen at once.

// React 18 Root API
import ReactDOM from 'react-dom/client';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);

// useTransition hook
const [isPending, startTransition] = useTransition();

startTransition(() => {
  // Non-urgent update (won't block UI)
  setFilter(newFilter);
});

Common Patterns

27. Controlled vs Uncontrolled Components

Controlled Components:

  • Form data handled by React state
  • Single source of truth
  • React controls the value
  • More code, more control

Uncontrolled Components:

  • Form data handled by DOM
  • Use refs to get values
  • Less code, less control
  • Good for simple forms
// Controlled
const [value, setValue] = useState('');
<input value={value} onChange={e => setValue(e.target.value)} />

// Uncontrolled
const inputRef = useRef();
<input ref={inputRef} defaultValue="initial" />
// Read value: inputRef.current.value

28. What are React Fragments?

Fragments let you group multiple children without adding an extra DOM element.

Why use them:

  • Avoid unnecessary div wrappers
  • Cleaner HTML output
  • Better for CSS (no extra container)
  • Required when returning multiple elements
// Long form
return (
  <React.Fragment>
    <ChildA />
    <ChildB />
  </React.Fragment>
);

// Short form (most common)
return (
  <>
    <ChildA />
    <ChildB />
  </>
);

29. What are React Portals?

Portals let you render children into a DOM node that exists outside the parent component's hierarchy.

Use cases:

  • Modals
  • Tooltips
  • Popovers
  • Dialogs

Why portals: Keeps the React component structure clean while rendering elsewhere in DOM.

// Modal renders at end of body, not inside parent
function Modal({ children }) {
  return ReactDOM.createPortal(
    children,
    document.getElementById('modal-root')
  );
}

// In HTML: <div id="modal-root"></div>

Best Practices

30. React Best Practices for 2026

  1. Use Functional Components - With hooks, classes are rarely needed
  2. Keep Components Small - One component, one responsibility
  3. Use TypeScript - Catches errors early, better documentation
  4. Follow Naming Conventions - PascalCase for components, camelCase for functions
  5. Destructure Props - Makes code cleaner: function User({ name, age })
  6. Use Fragment Over Div - When you don't need styling
  7. Memoize Wisely - Only when you measure performance issues
  8. Handle Loading & Error States - Better user experience
  9. Use Environment Variables - Don't hardcode API URLs
  10. Write Tests - Especially for complex logic
src/
ā”œā”€ā”€ components/     # Reusable components
ā”œā”€ā”€ features/       # Feature-specific components
ā”œā”€ā”€ hooks/          # Custom hooks
ā”œā”€ā”€ utils/          # Helper functions
ā”œā”€ā”€ services/       # API calls
ā”œā”€ā”€ store/          # State management
└── pages/          # Page components

Interview Coding Questions

31. Create a Counter Component

Build a counter with increment, decrement, and reset buttons.

Requirements:

  • Display current count
  • Buttons to increment/decrement
  • Reset to zero
  • Don't go below zero
function Counter() {
  const [count, setCount] = useState(0);
  
  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count > 0 ? count - 1 : 0);
  const reset = () => setCount(0);
  
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

32. Fetch and Display Data

Fetch users from an API and display them in a list.

Requirements:

  • Show loading state
  • Handle errors
  • Display user name and email
  • Retry on failure
function UserList() {
  const [users, setUsers] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users')
      .then(response => {
        if (!response.ok) throw new Error('Failed to fetch');
        return response.json();
      })
      .then(data => {
        setUsers(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);
  
  if (loading) return <div>Loading users...</div>;
  if (error) return <div>Error: {error}</div>;
  
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          <strong>{user.name}</strong> - {user.email}
        </li>
      ))}
    </ul>
  );
}

33. Todo List Application

Build a todo list with add, complete, and delete functionality.

Requirements:

  • Add new todos
  • Mark todos as complete
  • Delete todos
  • Show completed count
  • Filter (all/active/completed)
function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');
  
  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, {
        id: Date.now(),
        text: input,
        completed: false
      }]);
      setInput('');
    }
  };
  
  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ));
  };
  
  const deleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };
  
  const completedCount = todos.filter(t => t.completed).length;
  
  return (
    <div>
      <h2>Todos ({completedCount}/{todos.length})</h2>
      
      <div>
        <input
          value={input}
          onChange={e => setInput(e.target.value)}
          placeholder="Add new todo"
          onKeyPress={e => e.key === 'Enter' && addTodo()}
        />
        <button onClick={addTodo}>Add</button>
      </div>
      
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            <span style={{
              textDecoration: todo.completed ? 'line-through' : 'none',
              color: todo.completed ? '#999' : '#000'
            }}>
              {todo.text}
            </span>
            <button onClick={() => deleteTodo(todo.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Quick Reference

Essential Hooks Cheatsheet

  • useState - Add state to functional components
  • useEffect - Handle side effects (API, subscriptions)
  • useContext - Access context without prop drilling
  • useRef - Reference DOM elements or keep values between renders
  • useReducer - Complex state logic (like Redux)
  • useMemo - Memoize expensive calculations
  • useCallback - Memoize functions to prevent re-renders

Common Performance Issues & Solutions

  1. Too many re-renders → Use React.memo, useMemo, useCallback
  2. Large bundle size → Code splitting, dynamic imports
  3. Slow lists → Virtualization (react-window)
  4. Memory leaks → Cleanup in useEffect return
  5. Blocking UI → Use transitions (React 18)

Folder Structure Recommendations

src/
ā”œā”€ā”€ components/          # Shared components (Button, Input, Modal)
│   ā”œā”€ā”€ common/         # Very generic components
│   └── ui/             # UI-specific components
ā”œā”€ā”€ features/           # Feature-based components
│   ā”œā”€ā”€ auth/           # Login, register components
│   ā”œā”€ā”€ dashboard/      # Dashboard components
│   └── profile/        # User profile components
ā”œā”€ā”€ hooks/              # Custom hooks
ā”œā”€ā”€ utils/              # Helper functions
ā”œā”€ā”€ services/           # API services
ā”œā”€ā”€ contexts/           # React contexts
ā”œā”€ā”€ store/              # State management (Redux/Zustand)
└── pages/              # Page components