Episode 2 — React Frontend Architecture NextJS / 2.2 — React Components and Props
2.2 — React Components & Props: Quick Revision
Compact cheat sheet. Print-friendly. One section per sub-topic.
How to Use This Material
- Quick refresher — scan before interviews or coding sessions
- Spot check — if something looks unfamiliar, go back to the full sub-topic
- Flashcards — cover the right column in tables and test yourself
- Print it — keep next to your monitor during coding
2.2.a — Functional Components
| Concept | Key Point |
|---|---|
| Definition | A function that returns JSX |
| Naming | PascalCase, starts with uppercase |
| Return values | JSX, null, string, number, array, fragment, boolean (renders nothing) |
| Declaration vs Arrow | Both work. Arrows can't be hoisted. Team convention decides |
| Default export | export default function X() — one per file |
| Named export | export function X() — multiple per file, explicit imports |
| Barrel file | index.js that re-exports: export { Button } from './Button' |
// Minimum viable component
function Hello() {
return <h1>Hello</h1>;
}
2.2.b — Understanding Props
| Concept | Key Point |
|---|---|
| What are props | Inputs from parent, like function arguments |
| Data flow | One-way: parent → child only |
| Immutability | NEVER mutate props. Create copies |
| Destructuring | function Card({ title, size = "md" }) |
| Children | Special prop: content between <Tag>...</Tag> |
| Spread | {...props} forwards all properties |
| Callbacks | Functions as props for child → parent communication |
| Default values | Use default parameters, NOT defaultProps |
| TypeScript | interface Props { name: string; age?: number } |
// Destructure + defaults + children
function Card({ title, variant = "outlined", children }) {
return <div className={`card card-${variant}`}><h2>{title}</h2>{children}</div>;
}
Props vs State:
| Props | State | |
|---|---|---|
| Owner | Parent | Self |
| Mutable? | No | Yes (via setter) |
| Purpose | Configuration | Interactive data |
2.2.c — Dynamic Rendering
| Pattern | Syntax | Use When |
|---|---|---|
| Interpolation | {value} | Display data |
| AND operator | {condition && <X />} | Show/hide one thing |
| Ternary | {cond ? <A /> : <B />} | Choose between two |
| Early return | if (loading) return <Spinner /> | Handle edge cases first |
| Object lookup | const map = { a: <A/> }; map[key] | Multiple variants (>3) |
Gotcha: {0 && <X />} renders 0. Fix: {count > 0 && <X />}
// Number formatting
new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(29.99)
// → "$29.99"
2.2.d — Rendering Lists
// The pipeline
data
.filter(item => item.active) // Remove unwanted
.sort((a, b) => a.name.localeCompare(b.name)) // Order
.slice(0, 10) // Paginate
.map(item => <Card key={item.id} item={item} />) // Render
| Rule | Detail |
|---|---|
Use map() | Not forEach() (doesn't return) |
Always add key | On outermost element in map() |
| Never mutate | [...arr].sort(), not arr.sort() |
| Handle empty | Show <EmptyState /> when length === 0 |
| Handle loading | Show skeleton, not blank |
| Extract items | When item JSX > 10 lines → own component |
2.2.e — Keys in React
| Rule | Detail |
|---|---|
| Purpose | Track item identity across renders |
| Unique | Among siblings (different lists can reuse keys) |
| Stable | Same item = same key every render |
| Best keys | Database ID, UUID, slug, email |
| Bad keys | Math.random(), Date.now(), index (when list changes) |
| Index OK when | Static list, no reorder, no state in items |
The index-as-key bug:
Check item 0 → delete item 0 → item 1 slides to position 0 → inherits checked state
Fix: key={item.id} instead of key={index}
Key tricks:
// Force re-mount (reset state)
<EditForm key={selectedUserId} user={user} />
// Keys on fragments
<React.Fragment key={item.id}><dt/><dd/></React.Fragment>
// Composite keys
key={`${day}-${room}-${time}`}
Key is NOT a prop — props.key is undefined inside the component.
2.2.f — Reusable Card Component
Compound component pattern:
<Card variant="elevated">
<Card.Image src="..." alt="..." />
<Card.Header title="..." subtitle="..." />
<Card.Body>Content</Card.Body>
<Card.Footer><Button>Action</Button></Card.Footer>
</Card>
| Variant | Style |
|---|---|
outlined | Border, white bg, no shadow |
elevated | No border, white bg, box-shadow |
filled | No border, gray bg, no shadow |
Clickable card essentials:
cursor: pointerrole="button"+tabIndex={0}- Handle
EnterandSpacekeydown - Hover:
translateY(-2px)+ shadow increase - Use
<a>if it navigates,<div>+ onClick if it triggers action
Card grid:
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
Core Formulas
Component = f(props) → JSX
Props flow: Parent → Child (one-way)
Callback flow: Child → Parent (via function props)
Re-render triggers: props change OR state change
Key identity: same key = same component instance
Decision Quick-Reference
| Situation | Decision |
|---|---|
| Need to share data down | Use props |
| Child needs to tell parent | Pass callback as prop |
| Data goes through 4+ levels | Use Context (covered 2.13) |
| Multiple visual variants | Use variant prop |
| Complex component with sections | Compound component pattern |
| List with changing items | Use stable unique keys |
| Form with validation | Controlled inputs |
| Data-dependent UI | Dynamic rendering with &&/ternary |
Quick revision for 2.2 — React Components & Props
For deep dives, see the individual sub-topic files (2.2.a through 2.2.f)