Skip to content
SWENG.dev
Go back

React Interview

Edit page

Most Probable React Interview Questions (2025) — with thorough answers

Curated and ordered by likelihood based on common interview patterns for React engineers in 2024–2025. Answers are practical, detailed, and include pitfalls, examples, and “when to use” guidance.


1) What is the difference between functional and class components?

Example:

// Class component
class MyComponent extends React.Component {
  state = { count: 0 };
  render() {
    return (
      <button onClick={() => this.setState({ count: this.state.count + 1 })}>
        {this.state.count}
      </button>
    );
  }
}

// Functional component
function MyComponent() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

2) What’s the difference between props and state?

AspectPropsState
DefinitionData passed from parent to childData managed within the component
MutabilityImmutable (read-only in child)Mutable (via setState/useState)
OwnershipOwned by parent componentOwned by the component itself
UpdatesParent re-renders to pass new propsComponent calls setState to update
Use caseConfiguration, data flow downInteractive data, component memory

Key principles:

// ❌ Bad: Copying prop to state (gets out of sync)
function User({ name }) {
  const [userName, setUserName] = useState(name);
  // userName won't update if parent changes name prop
}

// ✅ Good: Use prop directly or with useMemo for derivation
function User({ name }) {
  const displayName = name.toUpperCase();
  return <div>{displayName}</div>;
}

3) Why shouldn’t you mutate state directly?

Directly mutating state (e.g., state.value = 123) in React is a common mistake. React relies on detecting changes to state objects to know when to re-render components. If you mutate state directly, React may not detect the change, leading to bugs and UI not updating as expected. Instead, always use the state updater function (e.g., setValue(newValue)) or return a new object/array when updating state.

Example:

// ❌ Bad: direct mutation
state.items.push(newItem);
setState(state);

// ✅ Good: create new array
setState({ ...state, items: [...state.items, newItem] });

4) How does React rendering work? What triggers re-renders and how do you avoid unnecessary ones?


5) What is the Virtual DOM and how does React use it?

Benefits:

Common misconception: VDOM isn’t always faster than direct DOM manipulation. For simple updates, direct DOM can be faster. VDOM’s value is in developer productivity and handling complex UIs declaratively.

// You write declarative code:
<button onClick={() => setCount(count + 1)}>{count}</button>

// React handles the imperative DOM updates:
// button.textContent = newCount;

6) What are keys in lists and why are they critical?

// ❌ Bad: using index as key in dynamic list
{
  items.map((item, i) => <Item key={i} {...item} />);
}

// ✅ Good: using stable unique ID
{
  items.map((item) => <Item key={item.id} {...item} />);
}

7) How do you debug a React component that renders incorrectly?

  1. Check props and state: Use React DevTools to inspect the component tree and see current props/state values.
  2. Add console.log: Log props, state, and key variables inside the render or effect functions.
  3. Simplify the component: Temporarily remove logic or children to isolate the problem.
  4. Check dependencies: Ensure useEffect/useMemo/useCallback dependencies are correct.
  5. Check keys: For lists, make sure keys are unique and stable.
  6. Look for warnings: Read the browser console for React warnings or errors.

8) What is the difference between server-side rendering (SSR) and client-side rendering (CSR)?

When to use:


9) What is Context? When to use it vs Redux Toolkit, Zustand, or React Query?


10) Controlled vs uncontrolled inputs. When to choose each?

// Controlled
const [v, setV] = useState('');
<input value={v} onChange={(e) => setV(e.target.value)} />;

// Uncontrolled
const r = useRef(null);
<input ref={r} defaultValue="hi" />;

11) What are custom hooks and why would you create one?

A custom hook is a JavaScript function whose name starts with use and that can call other hooks. Custom hooks let you extract and reuse stateful logic between components (e.g., form handling, data fetching, subscriptions) without duplicating code or using HOCs.

Example:

function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const onResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return width;
}

12) What is React.memo and when would you use it?

React.memo is a higher-order component that memoizes a functional component. It prevents unnecessary re-renders by shallowly comparing props. Use it for pure components that render the same output for the same props, especially in large lists or performance-sensitive trees.

Example:

const MyComponent = React.memo(function MyComponent(props) {
  // ...
});

13) How do you optimize performance in React applications?


14) How and when to use useMemo and useCallback? What can go wrong?


15) Data fetching in React: useEffect vs React Query/SWR. Which is better and why?


16) What are React Fragments and why use them?

Why use them:

// ❌ Bad: extra div in DOM
return (
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
);

// ✅ Good: no wrapper element
return (
  <>
    <h1>Title</h1>
    <p>Content</p>
  </>
);

// With keys (use full syntax)
{
  items.map((item) => (
    <React.Fragment key={item.id}>
      <dt>{item.term}</dt>
      <dd>{item.desc}</dd>
    </React.Fragment>
  ));
}

17) useRef — what is it and when do you use it?

useRef is a React Hook that returns a persistent, mutable object with a .current property. This object stays the same between renders. Updating ref.current does not cause a re-render, so refs are ideal for storing values that need to survive across renders but shouldn’t trigger UI updates.

When to use useRef:

Examples:

// Example 1: Keep previous value
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

// Example 2: Timer ref in TypeScript
function Timer(): JSX.Element {
  const intervalRef = (useRef < number) | (null > null);
  useEffect(() => {
    intervalRef.current = window.setInterval(() => console.log('tick'), 1000);
    return () => {
      if (intervalRef.current) window.clearInterval(intervalRef.current);
    };
  }, []);
  return <div>Timer running</div>;
}

Key pitfalls:

Common interview follow-up: If asked how to avoid stale closures in event listeners, explain that you can store the latest callback in a ref and always call ref.current from your event handler.


18) What are Higher-Order Components (HOCs)? When to use them vs hooks?

// Example HOC
function withAuth(Component) {
  return function AuthComponent(props) {
    const { user, loading } = useAuth();
    if (loading) return <Spinner />;
    if (!user) return <Redirect to="/login" />;
    return <Component {...props} user={user} />;
  };
}

// Usage
const ProtectedProfile = withAuth(Profile);

When to use HOCs:

When to use hooks instead:

// ✅ Better: custom hook
function useAuth() {
  const { user, loading } = useAuth();
  return { user, loading };
}

function Profile() {
  const { user, loading } = useAuth();
  if (loading) return <Spinner />;
  if (!user) return <Redirect to="/login" />;
  return <div>Welcome {user.name}</div>;
}


Edit page
Share this post on:

Previous Post
Node.js Interview
Next Post
Living as a Software Engineer in the US (Part 2)