React Interview Questions 11-15 (Data Flow, Context, Forms, State Management)

Welcome to Part 3 of our React interview preparation. We have covered components and hooks; now we need to talk about communication.

How does a component deep in the tree get data from the top? How do siblings share information? How do we handle form inputs? These are the architectural questions that define how scalable your application is. In this lesson, we will explore the patterns React provides to solve these problems, from simple "lifting state" to using global stores.

11. What is "Prop Drilling" and how do you avoid it?

Prop Drilling refers to the situation where you pass data (props) from a parent component down to a deeply nested child component, passing through several intermediate components that do not need the data themselves.

Why is it bad? It clutters the code of the intermediate components, makes refactoring difficult (if you rename the prop, you have to change it in 5 places), and triggers unnecessary re-renders in the middle layers.

Analogy: Imagine a Bucket Brigade fighting a fire. The water source is at the river (Parent), and the fire is at the house (Child). There are 10 people standing in between. To get the water to the fire, you have to pass the bucket to person 1, then 2, then 3... Person 5 doesn't care about the water; they just have to hold it and pass it. That is prop drilling.

// ❌ Prop Drilling Example
const App = () => {
  const user = "Alice";
  return <Navbar user={user} />; // App passes to Navbar
};

const Navbar = ({ user }) => {
  return <Profile user={user} />; // Navbar passes to Profile (doesn't use it)
};

const Profile = ({ user }) => {
  return <h1>Hello, {user}</h1>; // Finally used here
};

How to avoid it:

  • Context API: (See next question) Make data available globally.
  • Component Composition: Pass components themselves as children props, so the intermediate component doesn't need to know about the data.

12. What is the React Context API?

The Context API provides a way to pass data through the component tree without having to pass props down manually at every level. It is designed to share data that can be considered "global" for a tree of React components, such as the current authenticated user, theme, or preferred language.

  • createContext: Creates the Context object.
  • Provider: A component that supplies the data to the tree.
  • useContext: A hook consumed by children to access the data.

Analogy: Instead of passing a message by whispering it person-to-person (Prop Drilling), you use a Public Address (PA) system. You speak into the microphone (Provider), and anyone in the building who needs to hear it simply listens (useContext). The people in between don't need to repeat the message.

// 1. Create Context
const UserContext = React.createContext();

// 2. Provide Data
const App = () => {
  const user = "Alice";
  return (
    <UserContext.Provider value={user}>
      <Navbar />
    </UserContext.Provider>
  );
};

// 3. Intermediate components don't need props
const Navbar = () => {
  return <Profile />;
};

// 4. Consume Data directly
const Profile = () => {
  const user = React.useContext(UserContext);
  return <h1>Hello, {user}</h1>;
};

13. Controlled vs Uncontrolled Components?

This distinction typically refers to form inputs (input, textarea, select).

FeatureControlledUncontrolled
Source of TruthReact StateThe DOM
Update MethodonChange updates stateref reads value
ValidationInstant (on type)On Submit

Recommendation: Use Controlled components 95% of the time. They allow you to validate input, disable submit buttons, and enforce formats instantly. Use Uncontrolled for quick integrations with non-React libraries or simple file uploads.

// --- Controlled Component (Recommended) ---
const ControlledInput = () => {
  const [val, setVal] = React.useState("");

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

// --- Uncontrolled Component ---
const UncontrolledInput = () => {
  const inputRef = React.useRef();

  const handleSubmit = () => {
    alert("Value: " + inputRef.current.value);
  };

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleSubmit}>Submit</button>
    </>
  );
};

14. What is "Lifting State Up"?

In React, data flows one way: down. Sibling components cannot pass data directly to each other. If two siblings need to share the same state, you must "lift" that state up to their closest common ancestor. The parent manages the state and passes it down to both children via props.

Analogy: Two children (Siblings) are fighting over a toy. They cannot share it peacefully. The Parent (Ancestor) steps in, takes the toy (State), and decides who gets to play with it at what time, enforcing rules that both children must follow.

// Parent Component (Holds the State)
const Calculator = () => {
  const [temperature, setTemp] = React.useState("");

  return (
    <div>
      {/* Pass state and setter down */}
      <TemperatureInput temp={temperature} onChange={setTemp} scale="c" />
      <TemperatureInput temp={temperature} onChange={setTemp} scale="f" />
    </div>
  );
};

// Child Component (Stateless)
const TemperatureInput = ({ temp, onChange, scale }) => {
  return (
    <fieldset>
      <legend>Enter temperature in {scale}:</legend>
      <input value={temp} onChange={(e) => onChange(e.target.value)} />
    </fieldset>
  );
};

15. Context API vs Redux/Zustand: When to use a global store?

This is a very common architectural question. Both tools solve the problem of "global" state, but they work differently under the hood.

  • Context API: Built-in to React. Great for low-frequency updates (Theme, User Auth, Language). Downside: If the Context value changes, all components consuming that context re-render, which can cause performance issues for complex state.
  • Redux / Zustand (External Libraries): Optimized for high-frequency updates. They allow components to subscribe to slices of the state. If one part changes, only the components listening to that specific part re-render.

Rule of Thumb: Start with State and Props. If prop drilling gets annoying, use Context. If Context causes performance issues or your logic becomes spaghetti, move to Zustand or Redux.

You now understand how data flows through a React application. Whether it is simple parent-child communication, handling forms, or managing global themes, you have the patterns to handle it efficiently. In the next section, we will focus on performance—making sure your app stays fast as it grows.

🚀 Deep Dive With AI Scholar