I'm available for hiring. Hire now.

React Common Questions: A Comprehensive Guide

Profile picture

· By

Thiago Villa
Software Engineering

  • #react
  • #hooks
  • #performance
A left hand typing on a laptop
Photo Credit: Christopher Ayme

If I had a dollar for every time I got asked a React question in an interview, I’d probably have enough for a lifetime supply of coffee, which is—let's face it—fuel for coding. Over the years, I’ve noticed the same questions keep popping up—whether I’m being interviewed or helping others prep. To save everyone time, I’ve put together this guide. Think of it as my personal React FAQ, enjoy!


1. What is React and Why Use It?

React is an open-source JavaScript library developed by Facebook for building user interfaces, especially single-page applications (SPAs). It allows developers to create large web applications that can react to data changes and render efficiently.

Why use React?

  • Component-Based Architecture: Breaks UI into reusable components.
  • Declarative Syntax: Makes code more predictable and easier to debug.
  • Virtual DOM: Efficiently updates and renders components.
  • Strong Ecosystem: Rich set of tools, libraries, and community support.
  • Single-Page Applications (SPAs): Smooth navigation without full page reloads.
  • Static Deployment: Static files deployed to CDNs for scalability and performance.

2. What is the Virtual DOM (VDOM)

The VDOM is a lightweight, in-memory representation of the real DOM. After a state or prop change, React "diffs" (compares) the old and new VDOM to determine the minimal set of updates to the actual DOM, which is slow to update directly. That is called reconciliation.


3. What is JSX?

JSX stands for JavaScript XML. It is a syntax extension for JavaScript recommended for use with React (and similar frameworks) to describe the UI. A gross aproximation is that JSX is "HTML in JS" (although technically incorrect).

Example:

const element = <h1 className="greeting">Hello, world!</h1>;

Note 1: JSX uses camelCase property names (e.g., colSpan) and className/htmlFor for the HTML attributes class/for, since these are JavaScript reserved words.

Note 2: JSX is syntactic sugar for React.createElement(). Tools like Babel transpile it to regular JavaScript, which browsers can then read.

Example Above Transpiled:

const element = React.createElement(
  "h1",
  { className: "greeting" },
  "Hello, world!"
);

4. What are Components?

Components are the building blocks of React. They encapsulate logic, structure, and styling, making code modular and reusable. There are two types of components:

  • Class Components: ES6 classes that extend React.Component, have state, lifecycle methods, and more verbose syntax. Still used in legacy code.
  • Functional Components: JavaScript functions that return JSX, use hooks for state and lifecycle events and have simpler syntax. Modern way of writing React.

Example:

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

// Function component
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// Usage (both)
<Welcome name="Alice" />;

5. What are Props?

Props (short for "properties") are read-only inputs passed from parent to child components. They enable unidirectional data flow through the component tree. See prop drilling.

Example:

function Greeting(props) {
  return <h1>Hello, {props.name}!</h1>;
}

// Usage
<Greeting name="Alice" />;

6. What is State?

State is a built-in object created via the useState hook that adds data to a component. The state setter schedules an update and subsequent re-render. The functional update form (setCount(c => c++)) avoids stale state issues with rapid/batch renders.

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count => count + 1)}>Click me</button>
    </div>
  );
}

7. What are Hooks?

Hooks are functions that add state and lifecycle methods to functional components. They were introduced in React 16.8. The most common hooks are:

  • useState: Adds state to functional components.
  • useEffect: Performs side effects (e.g., data fetching).
  • useRef: Keeps references across renders.
  • useContext: Accesses context values.
  • useMemo: Caches expensive calculations.
  • useCallback: Caches callback functions.
  • useReducer: Manages complex state with a reducer.

8. What is the useEffect Hook?

useEffect runs side effects, such as data fetching, event subscriptions, timers, or DOM manipulation. It introduces lifecycle methods to functional components via the dependency array:

  • []: Once on mount (first render)
  • [dep]: When dep changes
  • Omitted: After every render

The return function runs cleanup on unmount (e.g., unsubscribing or clearing timers):

useEffect(() => {
  const id = setInterval(doSomething, 1000);
  return () => clearInterval(id); // On unmount
}, []); // On mount

Fetch data inside useEffect to avoid stale props/state:

useEffect(() => {
  async function fetchData() {
    const response = await fetch(`/api/data/${userId}`);
    setData(await response.json());
  }
  fetchData();
}, [userId]); // 'userId' prop/state

9. What is the useRef Hook?

useRef returns a mutable ref object whose .current property persists across renders. Common uses include storing timer IDs and direct access to the DOM.

Example:

const inputRef = useRef();

function focusInput() { inputRef.current.focus(); }

<input ref={inputRef} />
<button onClick={focusInput}>Focus</button>

10. How Does Data Flow in React?

React uses one-way data flow (unidirectional data flow), from parent to child via props. Pass a callback function as prop to update data in the parent. See lifting state.

Example:

function Parent() {
  const [value, setValue] = useState("");
  return <Child onChange={setValue} />; // 'setValue' is a callback
}

function Child({ onChange }) {
  return <input onChange={e => onChange(e.target.value)} />;
}

11. What is Lifting State Up?

"Lift" the state up to the nearest common ancestor to share state between multiple child components via props. See prop drilling and context API.

Example:

function Parent() {
  const [sharedValue, setSharedValue] = useState("");

  return (
    <>
      <ChildA value={sharedValue} onChange={setSharedValue} />
      <ChildB value={sharedValue} />
    </>
  );
}

12. What is Prop Drilling?

Prop drilling occurs when props pass down through many layers of components, even if only the deepest child needs it. Use the Context API or state management libraries instead.

Example:

function Grandparent({ user }) {
  return <Parent user={user} />;
}

function Parent({ user }) {
  return <Child user={user} />;
}

function Child({ user }) {
  return <div>Hello, {user.name}!</div>;
}

// 'user' is passed through every level, even if only Child needs it.

13. What is the Context API?

The Context API shares values between components without passing props manually at every level. It replaces prop drilling. Common uses include themes, user info, and app settings.

Example:

const ThemeContext = React.createContext("light");

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

function Toolbar() {
  return <ThemedButton />;
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>Button</button>;
}

⚠️ Common Issue: Overusing context or storing large, frequently changing objects triggers unnecessary re-renders. Use only for global, stable values. See performance.


14. What is Redux?

Redux is a state management library often used with React for managing complex state in large applications in a predictable way. It consists of:

  • Store: Holds the state.
  • Actions: Describe state changes.
  • Reducers: Specify how state changes.

Example:

import { useSelector, useDispatch } from "react-redux";

function Counter() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  return (
    <button onClick={() => dispatch({ type: "INCREMENT" })}>
      Count: {count}
    </button>
  );
}

// Store/reducer not shown

15. What is useReducer?

useReducer manages complex state in large applications. It is an alternative to Redux and other state management libraries.

When to use useReducer:

  • When state logic is complex or involves multiple sub-values.
  • When the next state depends on the previous state.
  • When you want to group related state updates together.

Example:

import { useReducer } from "react";

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

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </>
  );
}

Summary:
Use useReducer for state that is complex, deeply nested, or when you want to centralize state updates in one place.


16. How to Handle Forms in React?

React handles forms using controlled components, where form data is handled by the component's state.

Example:

function MyForm() {
  const [value, setValue] = useState("");

  const handleSubmit = e => {
    e.preventDefault();
    alert("Submitted: " + value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={value} onChange={e => setValue(e.target.value)} />
      <button type="submit">Submit</button>
    </form>
  );
}

17. What are Controlled vs Uncontrolled Components?

  • Controlled: Form data is handled by React state.
  • Uncontrolled: Form data is handled by the DOM.

Controlled Example:

<input value={value} onChange={e => setValue(e.target.value)} />

Uncontrolled Example:

<input ref={inputRef} />

18. What are Keys in React Lists?

Keys help React identify which list items have changed, are added, or are removed. They should be unique and stable, such as IDs.

Example:

const items = ["A", "B", "C"];
const list = items.map(item => <li key={item}>{item}</li>);

19. What Are the Main Performance Issues in React?

  • Unnecessary Re-Renders: Caused by unmemoized function/object props, large objects in context, or non-unique/unstable keys in lists.
  • Slow Rendering/Sluggish UI: Caused by large/deeply nested trees, unvirtualized lists/tables with ~1,000s of items/cells, or CPU-intensive calculations in the main thread.
  • Long Initial Load Time: Loading too much code up front.

20. What is Server-Side Rendering (SSR)?

SSR renders React components on the server and sends HTML to the client. This improves SEO and initial load performance. Frameworks like Next.js make SSR with React easy.


21. How to Test React Components?

  • React Testing Library: For unit and integration testing.
  • Cypress: For end-to-end (E2E) testing in the browser.
  • Playwright: For cross-browser E2E testing and automation.

Example with React Testing Library:

import { render, screen } from "@testing-library/react";

function MyComponent() {
  return <div>Hello, world!</div>;
}

test("renders greeting", () => {
  render(<MyComponent />);
  expect(screen.getByText(/hello/i)).toBeInTheDocument();
});

22. What is an Error Boundary?

Error boundaries are React components that catch JavaScript errors in their child component tree and display a fallback UI. This is still a primary use case for class components.

Example:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

23. How to Style React Components?

  • CSS Modules: Scoped CSS files to avoid class name clashes.
  • Styled Components: CSS-in-JS for dynamic, component-level styles.
  • Inline Styles: style prop for quick, simple styles (no pseudo-selectors/media queries).

24. How To Debug React Applications?

  • React Dev Tools: Inspect the component tree, props, state, and re-renders.
  • Console Logging: Use console.log for quick checks.
  • Browser DevTools: Set breakpoints and step through code.
  • Error Boundaries: Catch and display UI errors.
  • Strict Mode: Use <React.StrictMode> to highlight issues.
  • Linting/Type Checking: Use ESLint and TypeScript to catch bugs early.

Example:

import React from "react";

function MyComponent({ value }) {
  React.useEffect(() => {
    console.log("Value changed:", value);
  }, [value]);

  return <div>{value}</div>;
}

Tip: Use the React DevTools "Highlight Updates" feature to visualize unnecessary re-renders.


Conclusion

React is a powerful library with a rich ecosystem and a vibrant community. Understanding its core concepts—components, state, props, hooks, and more—will help you build robust and maintainable applications. Whether you're just starting or looking to deepen your knowledge, these common questions and answers should serve as a helpful reference on your React journey.

Thiago Villa

About the Author

Thiago Villa - Senior Fullstack Software Engineering Consultant

I build sturdy, structured, and scalable software designed to grow, adapt, and withstand the test of time.

Made with ❤️ in Vale do Coquinho.

© 2024 Thiago Villa. All rights reserved.