Beginner4 questionsFull Guide

React Props & One-Way Data Flow — Complete Interview Guide

Master React props — immutability, one-way data flow, lifting state up, the children prop, prop drilling, and the TypeScript patterns for typing props correctly in every interview scenario.

The Mental Model

Props are a component's function arguments — read-only data that flow from parent to child. State is a component's private memory — data it owns and can change. React enforces one-directional data flow: data only moves down through props; changes move back up through callback functions passed as props. This one-way street is what makes React apps predictable — you always know where data lives, and there is exactly one way it can change.

The Explanation

Props Are Function Arguments

A React component is a function. Props are its arguments. Just as you can't modify a function argument inside the function body without side effects, a component must never modify its props:

// Component receives props like function arguments
function Greeting({ name, age }) {
  // ❌ Never do this — props are read-only
  name = 'Bob'; // this is a local mutation, doesn't affect the parent anyway

  return <p>Hello, {name}. You are {age} years old.</p>;
}

// Parent controls what props the child receives
<Greeting name="Alice" age={30} />

If a component receives an incorrect prop, the fix is to change what the parent passes — not to modify the prop inside the child.

One-Way Data Flow

Data in React flows in one direction: parent → child via props. A child component cannot directly change its parent's state. This makes the data flow predictable:

function Parent() {
  const [count, setCount] = useState(0);

  // Data flows DOWN via props
  return <Child count={count} onIncrement={() => setCount(c => c + 1)} />;
}

function Child({ count, onIncrement }) {
  // Child reads data from props — cannot directly change parent state
  // Changes move UP via callback props
  return <button onClick={onIncrement}>Count: {count}</button>;
}

To send data "up" the tree, a parent passes a callback function as a prop. The child calls the callback with the new value; the parent updates its state; React re-renders both with the new value. This is the only correct way for a child to influence its parent.

Lifting State Up

When two sibling components need to share state, the state must live in their closest common ancestor — this is "lifting state up":

// ❌ Each component has its own state — they can't share it
function TempInput() { const [val, setVal] = useState(0); ... }
function TempDisplay() { const [val, setVal] = useState(0); ... } // separate, can't sync

// ✅ State lifted to the parent — both siblings share the same source of truth
function TemperatureConverter() {
  const [celsius, setCelsius] = useState(0);

  return (
    <>
      <CelsiusInput  value={celsius}     onChange={setCelsius} />
      <FahrenheitDisplay celsius={celsius} />
    </>
  );
}

The children Prop

Any JSX you nest between a component's opening and closing tags becomes its children prop. This is how composable layout components are built:

function Card({ title, children }) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <div className="card-body">{children}</div>
    </div>
  );
}

// Anything between <Card> tags becomes children
<Card title="User Profile">
  <Avatar src={user.avatarUrl} />
  <p>{user.bio}</p>
</Card>

Prop Drilling — The Problem, Not the Solution

Prop drilling is when a prop is passed through multiple intermediate components that don't use it — they just relay it to a deeper child. It becomes a maintenance problem when the prop needs to reach many levels deep:

// Prop drilling — userId passes through App → Layout → Sidebar → UserMenu
// Layout and Sidebar don't need userId at all
function App() {
  return <Layout userId={user.id} />;
}
function Layout({ userId }) {
  return <Sidebar userId={userId} />;
}
function Sidebar({ userId }) {
  return <UserMenu userId={userId} />;
}
function UserMenu({ userId }) {
  return <a href={`/users/${userId}`}>Profile</a>;
}

Solutions: React Context (for ambient data read by many components), component composition (pass the rendered element as a prop instead of the data), or state management libraries for complex cases.

TypeScript Prop Typing

Always type props explicitly — it serves as documentation and catches mistakes at compile time:

// Inline type — good for simple components
function Button({ label, onClick, disabled = false }: {
  label: string;
  onClick: () => void;
  disabled?: boolean;  // optional prop — ? makes it optional, with default
}) {
  return <button onClick={onClick} disabled={disabled}>{label}</button>;
}

// Interface — good for larger or reused prop shapes
interface UserCardProps {
  user: {
    id: string;
    name: string;
    avatarUrl?: string;  // optional
  };
  onSelect: (id: string) => void;
  className?: string;
}

function UserCard({ user, onSelect, className }: UserCardProps) {
  return (
    <div className={className} onClick={() => onSelect(user.id)}>
      {user.name}
    </div>
  );
}

Props vs State — The Decision Rule

A simple framework for deciding where data should live:

  • If the data comes from outside the component (passed by a parent) → it's a prop
  • If the component owns and controls the data → it's state
  • If multiple components need the same data → lift it to the closest common ancestor
  • If many disconnected components need it → Context or external state management

Common Misconceptions

⚠️

Many developers think they can mutate props to update the UI — props are read-only in the component that receives them. Mutating a prop changes a local reference; it doesn't update the parent's state or trigger a re-render. To change what a child displays, the parent must pass different props.

⚠️

Many developers confuse one-way data flow with 'children can never affect parents' — children CAN affect parents through callback props. The data (state) lives in the parent; the child calls the callback to request a change; the parent decides whether and how to update its state. Data still flows down; control flows up through function calls.

⚠️

Many developers think prop drilling is unavoidable and immediately reach for Context or Redux — often the right fix for prop drilling is composition: instead of drilling userId down through Layout, have App render UserMenu directly inside Layout via children. Restructuring the component tree often eliminates drilling without adding Context.

⚠️

Many developers think the children prop is special React magic — children is just a regular prop whose value is whatever JSX you put between the component's open and closing tags. It works identically to any other prop; you can even rename it: function Modal({ content }) { ... } and pass it as <Modal content={<p>hi</p>} />.

⚠️

Many developers add defaultProps to functional components — defaultProps is deprecated for function components (and removed in React 19 for function components). Use JavaScript default parameter values instead: function Btn({ label = 'Click me' }). This is simpler, works with TypeScript, and is the current standard.

⚠️

Many developers think passing too many props (10+) always means the component needs refactoring — sometimes a complex component genuinely needs many inputs. The issue is when props are structurally tangled (a prop only makes sense in combination with another). Group related props into an object, or break the component into smaller pieces, but don't refactor just because the prop count is high.

Where You'll See This in Real Code

Design system components: a Button component has props for variant, size, disabled, onClick, and children. Its strict prop interface means every consumer is forced to use the component the intended way — no rogue inline styles.

Form field components: a controlled TextField takes value, onChange, label, error, and helperText as props. The parent form owns the state; the TextField is purely presentational — it receives data and emits changes via callbacks.

List items in a data table: a TableRow receives the row data object as a prop and an onSelect callback. The parent Table manages which row is selected; the TableRow calls onSelect when clicked, lifting the selection event up.

Compound components: a Tabs component passes the selected tab index and an onChange callback to TabList and TabPanel children via the children prop pattern — the parent Tabs owns the state, the children are controlled.

React Router Link: the to prop controls where the link navigates. This is a standard controlled-via-props pattern — the Link component has no opinion about destination; the parent tells it where to go.

Next.js page components: page components receive params (route params), searchParams (query string), and no other React props — Next.js passes route information as props, demonstrating how framework data flows into components via the standard props mechanism.

Interview Cheat Sheet

  • Props = function arguments — read-only, flow from parent to child only
  • State = component's private memory — owned and mutable by the component itself
  • One-way data flow: data moves DOWN via props, changes move UP via callback props
  • To change parent state from a child: parent passes a callback as prop, child calls it
  • Lifting state up: when siblings need shared state, move it to their closest common ancestor
  • children prop: JSX between a component's open and close tags — a regular prop with special JSX syntax
  • Prop drilling: when props pass through components that don't use them — solve with Context or composition
  • TypeScript: use interface or inline type for props; use ? for optional props; use default params for defaults
  • defaultProps is deprecated for function components in React 19 — use default parameter values
💡

How to Answer in an Interview

  • 1.State the one-way flow rule clearly up front: 'React enforces one-directional data flow — data moves down from parent to child via props. To send changes back up, a child calls a callback function that the parent passed as a prop. The parent controls the state; the child just requests changes.'
  • 2.The lifting state up explanation shows you understand the core React mental model: 'When two siblings need to share state, the state belongs in their closest common ancestor. The ancestor owns the state and passes both the value and the setter down as props to both siblings. This keeps one source of truth.'
  • 3.For prop drilling, give a two-solution answer: 'Prop drilling happens when data passes through intermediaries that don't use it. The first fix I try is component composition — restructure so the component that needs the data is rendered higher up and passed via children. If the data is truly ambient (many unrelated components need it), then Context is the right tool.'
  • 4.The props vs state decision framework shows senior thinking: 'I ask: who owns this data? If it comes from outside, it's a prop. If the component creates and controls it, it's state. If multiple sibling components need the same value, I lift it to their common parent. If disconnected components across the tree need it, I use Context or an external store.'
  • 5.TypeScript props are worth mentioning: 'I always type props explicitly with an interface or inline type. It serves as documentation for how the component should be used, catches misuse at compile time, and shows up in IDE autocomplete for everyone who uses the component.'
  • 6.The children prop insight separates candidates: 'children is just a regular prop — nothing magic about it. You can rename it, pass it explicitly as a prop attribute, or accept multiple named slots. Understanding this unlocks composition patterns like compound components where you pass rendered elements as props.'

Practice Questions

4 questions
#01

What are props and how is prop drilling a problem?

EasyReact Fundamentals💡 Props pass data down; drilling = passing through many layers just to reach a deeply nested child
#02

What is the difference between state and props?

EasyReact Fundamentals PRO💡 Props = external inputs (immutable); state = internal memory (mutable via setState)
#03

What is the Render Props pattern and when would you still use it?

EasyComponent Patterns PRO💡 Pass a function as a prop that returns JSX — the component calls it with its internal state
#04

Render props — caller controls rendering

HardComponent Patterns
MetaAtlassianCRED+1

Related Topics

useState Hook — Complete React Interview Guide
Beginner·4–8 Qs
React Component Lifecycle — Complete Interview Guide
Intermediate·10–15 Qs
Rendering Reconciliation
Advanced·4–8 Qs
React Context API — Complete Interview Guide
Intermediate·8–12 Qs
🎯

Can you answer these under pressure?

Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.

Practice Free →Try Output Quiz