Components and Props
A component is a function from inputs to UI, and the inputs only flow down
Guess first
Pick an answer. You will see if you were right at the end of the lesson.
A child component needs to tell its parent that a button was clicked. What is the normal way?
Real-world analogy
What is it?
A React component is a function that receives props and returns JSX, a description of the UI. React calls the function and compares the new description with the old one. It updates only the parts of the page that changed. Props are the inputs and they flow from parent to child. Data goes down as props and events go up as callbacks, so you can trace where a value came from.
Real-world relevance
A user directory page renders a list of cards. Each card is one component that gets a user, an optional highlight flag and an onSelect callback. The same card is reused on the search page and the team page. When the design changes, you edit one file. A wrong prop name or a missing field shows up as a TypeScript error in the editor. It does not show up as a blank card in production.
Key points
- A component is a function — It takes props as one object and returns what the screen should show. React calls it again whenever its inputs change.
- JSX is a function call — The tag <Card name="Ada" /> compiles to a call that makes a description of the UI. It looks like HTML but it is JavaScript, so it uses className and curly braces.
- Props flow down, read-only — A parent passes props to a child, and the child must not change them. If the child needs a change, the parent has to make it.
- Type props with a type — Write type CardProps = { name: string } and annotate the function argument. The compiler then flags a missing or wrong prop before the page runs.
- Optional props and defaults — Mark a prop with ? when it may be missing. Give it a default in the destructuring, such as highlight = false.
- children is a prop — Whatever you put between the tags arrives as children. Type it as ReactNode so the parent can pass text, elements or lists.
- Callbacks send events up — The parent passes a function such as onSave. The child calls it, and the parent decides what to do with the result.
- Keys identify list items — React uses key to match old items to new ones. Use a stable id, because an index key attaches state to a position instead of to the item.
- Compose before drilling — Passing a prop through three layers is a hint to restructure. Often you can pass the finished element as children instead.
Quick check
Answer from memory — scrolling up first makes it stick less.
Why is key={index} a poor choice for a list that can be reordered?
What does the ? in the type { highlight?: boolean } mean?
Code example
import type { ReactNode } from 'react';
type User = { id: number; name: string; role?: string };
type UserCardProps = {
user: User;
highlight?: boolean;
onSelect: (id: number) => void;
children?: ReactNode;
};
export function UserCard({ user, highlight = false, onSelect, children }: UserCardProps) {
return (
<li className={highlight ? 'card highlight' : 'card'}>
<h3>{user.name}</h3>
<p>{user.role ?? 'Member'}</p>
<button type="button" onClick={() => onSelect(user.id)}>Select</button>
{children}
</li>
);
}
export function UserList({ users }: { users: User[] }) {
const handleSelect = (id: number) => console.log('selected', id);
return (
<ul>
{users.map(u => (
<UserCard key={u.id} user={u} onSelect={handleSelect} highlight={u.role === 'admin'} />
))}
</ul>
);
}Line-by-line walkthrough
- 1. This is one file with two components. The User type has an optional role, marked with a question mark.
- 2. UserCardProps types every prop: highlight is optional, onSelect is a function that takes an id, and children can be any renderable content.
- 3. UserCard destructures its props and gives highlight a default of false, so callers can leave it out.
- 4. The button calls onSelect with the user id when clicked. The card never changes the user object it received.
- 5. UserList defines one handler and passes it down as a callback prop to every card.
- 6. Each card in map gets key={u.id}, a stable id that stays with the user even if the list is reordered.
Spot the bug
type Row = { id: number; label: string };
function Rows({ rows }: { rows: Row[] }) {
return (
<ul>
{rows.map((row, index) => (
<li key={index}>
<input defaultValue={row.label} />
</li>
))}
</ul>
);
}Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- Passing Props to a Component (React)
- Rendering Lists (React)
- Free Full-Stack Playbook (React and TypeScript lessons) (Teamz Lab)
Lock it in