What Are Default Props in React?
Advertisement
🧩 Scenario
Architecture Walkthrough
Destructuring Defaults in Functional Components
ES6 destructuring allows default values directly in the parameter list: function Avatar({ name = 'Anonymous', size = 40 }). When a caller omits the name prop or passes undefined, the default 'Anonymous' applies. This is the idiomatic approach in modern React functional components.
The defaults are co-located with the prop names, making the component signature self-documenting. A reader can see both the prop name, its type, and its default value at a glance without searching for a separate defaultProps block.
undefined vs null
Destructuring defaults trigger only for undefined, not for null. This is standard JavaScript: const { x = 5 } = { x: null } yields x = null, not x = 5. Passing null explicitly means the caller intentionally provided "no value" and the component should handle it accordingly (often rendering nothing). This distinction matters for nullable props that a caller may need to explicitly clear.
Component.defaultProps Is Deprecated
The Component.defaultProps static property was the original API for default props. It was deprecated in React 18.3 for functional components (it was never useful for function components with TypeScript since it defeated type inference) and will eventually be removed. Do not use it in new code.
Object and Array Defaults
Inline object or array literals as default props create a new reference on every render: function List({ items = [] }) produces a new [] reference every time the component renders without the items prop. If any downstream logic uses reference equality on items (like React.memo or a useEffect dependency), this creates issues. The solution is to define the default outside the component as a stable constant.
Key Code Explained
// TypeScript: mark optional props with ? and pair with defaults
interface ButtonProps {
children: React.ReactNode; // required — no default
variant?: 'primary' | 'secondary' | 'ghost'; // optional
size?: 'sm' | 'md' | 'lg'; // optional
disabled?: boolean; // optional
onClick?: () => void; // optional
}
function Button({
children,
variant = 'primary',
size = 'md',
disabled = false,
onClick,
}: ButtonProps) {
return (
<button
className={`btn btn--${variant} btn--${size}`}
disabled={disabled}
onClick={onClick}
>
{children}
</button>
);
}
// All valid:
<Button>Save</Button> // primary, md, not disabled
<Button variant="ghost" size="sm">Cancel</Button>
<Button disabled>Processing...</Button>
<Button variant={null as any}>Save</Button> // null bypasses default — variant is null
// Stable default for object/array props
// Bad: new [] reference on every render when items is undefined
function BadList({ items = [] }: { items?: string[] }) {
return <ul>{items.map((i) => <li key={i}>{i}</li>)}</ul>;
}
// Good: stable constant outside the component
const EMPTY_ITEMS: string[] = [];
function GoodList({ items = EMPTY_ITEMS }: { items?: string[] }) {
return <ul>{items.map((i) => <li key={i}>{i}</li>)}</ul>;
}
// React.memo on GoodList correctly skips re-renders when items is undefined
// because EMPTY_ITEMS is always the same reference
// Component.defaultProps — deprecated, do not use
// Bad:
function Avatar({ name, size }: AvatarProps) {
return <div className="avatar">{name[0]}</div>;
}
Avatar.defaultProps = { name: 'Anonymous', size: 40 }; // deprecated in React 18.3
// Good: destructuring defaults
function Avatar({ name = 'Anonymous', size = 40 }: AvatarProps) {
return <div className="avatar" style={{ width: size, height: size }}>{name[0]}</div>;
}
// Distinguishing required vs optional in TypeScript
interface CardProps {
title: string; // required — no default, no ?
subtitle?: string; // optional — can be omitted, defaults to undefined
imageUrl?: string; // optional — component handles undefined case
}
function Card({ title, subtitle, imageUrl }: CardProps) {
return (
<div className="card">
{imageUrl && <img src={imageUrl} alt={title} />}
<h3>{title}</h3>
{subtitle && <p>{subtitle}</p>}
</div>
);
}
The subtitle && <p>{subtitle}</p> pattern is cleaner than setting a default for subtitle because subtitle genuinely may not exist. Providing a default empty string would cause an empty <p> element to render. Keeping it as undefined and guarding with && renders nothing when the subtitle is absent.
Tradeoffs
| Default approach | Works in TypeScript | Co-located | Stable reference | Recommended |
|---|---|---|---|---|
| Destructuring inline | Yes | Yes | Primitives only | Yes |
| Constant outside component | Yes | No | Yes | For objects/arrays |
| Component.defaultProps | Partially | No | Yes | No (deprecated) |
What Interviewers Actually Check
- Whether you use destructuring defaults rather than
Component.defaultProps - Whether you know
nullbypasses destructuring defaults - Whether you know
Component.defaultPropsis deprecated - Whether you mark optional props with
?in TypeScript - Whether you know about the object/array reference stability issue with inline defaults
Follow-Up Questions
- How does TypeScript infer the return type of a component when optional props have default values that make them effectively always defined inside the function?
- How would you create a variant system for a button component with TypeScript discriminated unions for
variantandsize? - When would you use
React.forwardRefin combination with default props? - If you are wrapping a third-party component in your own, how do you pass default props to the inner component while still allowing the caller to override them?
- How do default props interact with
React.memo: if a default prop creates a new object reference, does it prevent memoization?
Common Candidate Mistakes
- Using
Component.defaultPropsin new functional components when destructuring defaults are the correct modern approach - Not knowing that
nullbypasses destructuring defaults, leading to bugs when callers explicitly clear a prop - Providing an inline object or array as a default without knowing it creates a new reference on every render
- Not marking optional props with
?in TypeScript, making the type system believe they are always provided - Setting a default for a prop that should be required, hiding the bug where the caller forgot to pass it
Interview Readiness Checklist
Before you leave this question, make sure you can answer:
- Can you write a functional component with optional TypeScript props and destructuring defaults?
- Can you explain the difference between
undefined(triggers default) andnull(bypasses default)? - Can you explain why
Component.defaultPropsis deprecated and should not be used? - Can you handle object and array defaults without causing referential instability?
- Can you distinguish which props are required vs optional in a TypeScript interface?
Summary
Default prop values in functional components are set using ES6 destructuring defaults directly in the function parameter list. When a prop is omitted or explicitly passed as undefined, the default value applies. When a prop is explicitly passed as null, the default does not apply. This distinction is intentional: undefined means "not provided," while null means "intentionally absent."
Component.defaultProps is the legacy API for default props and is deprecated in React 18.3. It should not be used in new functional components. Destructuring defaults are cleaner, co-located with the parameter definition, and work correctly with TypeScript type inference, which defaultProps did not.
For object or array defaults, defining the default as a stable constant outside the component prevents a new reference from being created on every render. This matters for memoized components and effects that use the prop as a dependency, where a new reference on every render defeats the optimization.
What is the difference between undefined and null for default props?
Destructuring defaults only trigger when the value is undefined, not when it is null. Passing null explicitly bypasses the default. This is intentional: null means "no value" was deliberately passed, while undefined means the prop was omitted.
Advertisement
Stay Updated
Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.
Advertisement