React: From Components to Production · Components and JSX
Components and Props
Build reusable components with typed props and default values.
Components are functions that take props and return JSX. Props flow one way (parent → child) and are read-only. Type them with TypeScript, give defaults with destructuring, and spread remaining props onto underlying elements for flexible primitives. Since React 19, ref can be passed as a regular prop to function components (no forwardRef needed).
import type { ComponentProps } from "react";
type ButtonProps = ComponentProps<"button"> & {
variant?: "primary" | "secondary";
loading?: boolean;
};
export function Button({ variant = "primary", loading = false, children, disabled, ...rest }: ButtonProps) {
return (
<button className={`btn btn-${variant}`} disabled={disabled || loading} aria-busy={loading} {...rest}>
{loading ? "Saving…" : children}
</button>
);
}
// Usage
<Button type="submit" loading={isSaving} onClick={() => console.log("clicked")}>Save</Button>
export function Button({ variant = "primary", loading = false, children, disabled, ...rest }) {
return (
<button className={`btn btn-${variant}`} disabled={disabled || loading} aria-busy={loading} {...rest}>
{loading ? "Saving…" : children}
</button>
);
}
// Usage
<Button type="submit" loading={isSaving} onClick={() => console.log("clicked")}>Save</Button>
Common pitfalls
- Mutating props or objects received through props.
- Huge components with dozens of props — split them or use composition.
- Defining components inside other components (they remount on every render).
Key points
- Props are read-only inputs
- Type props; default via destructuring
- ref is a normal prop in React 19
Further reading: react.dev: Passing props
Practice questions
Why shouldn't you define a component inside another component's body?
Answer
A new component type is created on every render, so React unmounts and remounts it each time, losing state and hurting performance. Define components at module level.
How do you accept all native button attributes in a custom Button?
Answer
Type props as ComponentProps<'button'> (plus your own) and spread the remaining props onto the <button> element.
Open in the app to mark lessons complete, take notes and track your progress.