Components & JSX
Functional components, JSX, props, composition, conditional rendering
React applications are built from components — JavaScript functions that accept props and return JSX describing what should appear on the screen. Understanding how React renders, reconciles the virtual DOM, and when it re-renders is the foundation for writing correct, performant React code.
Key Points
- Functional components: const MyComponent = (props) => <div>{props.title}</div> — plain functions, no class required
- JSX: syntactic sugar for React.createElement() — compiled by Babel/SWC; className not class, htmlFor not for
- Props: read-only input data passed from parent to child — never mutate props directly
- Keys in lists: unique stable identifier for each list item — helps React reconciler identify moves vs remounts; use id, not array index
- Conditional rendering: ternary {condition ? <A/> : <B/>}, logical AND {condition && <A/>}, or separate variables
- Composition: pass components as children or props — React.ReactNode type for anything renderable
- Reconciliation (diffing): React compares previous vs new virtual DOM tree — same type → update, different type → unmount + mount
- React 18 automatic batching: multiple setState calls in async handlers / timeouts are batched into one render
- StrictMode: double-invokes effects and renders in development to expose side effects — no production impact
React components: typed props, list rendering with keys, composition with children, conditional rendering
// Functional component with typed props
interface UserCardProps {
user: { id: number; name: string; avatar: string };
onSelect: (id: number) => void;
isSelected?: boolean;
}
const UserCard: React.FC<UserCardProps> = ({ user, onSelect, isSelected = false }) => {
return (
<div
className={`card ${isSelected ? 'card--selected' : ''}`}
onClick={() => onSelect(user.id)}
>
<img src={user.avatar} alt={user.name} />
<h3>{user.name}</h3>
</div>
);
};
// List rendering — stable keys
const UserList = ({ users }: { users: User[] }) => (
<ul>
{users.map(user => (
<UserCard key={user.id} user={user} onSelect={handleSelect} />
))}
</ul>
);
// Composition — children and render props
interface ModalProps {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
title: string;
}
const Modal = ({ isOpen, onClose, children, title }: ModalProps) => {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-box" onClick={e => e.stopPropagation()}>
<header>
<h2>{title}</h2>
<button onClick={onClose}>✕</button>
</header>
<main>{children}</main>
</div>
</div>
);
};
// Usage:
// <Modal isOpen={open} onClose={() => setOpen(false)} title="Edit User">
// <UserEditForm user={selectedUser} />
// </Modal>Real-World Example
Using array index as a React key is a common mistake that causes subtle bugs — when items are reordered or deleted, React reuses DOM elements by key. If key=index, moving item[0] to position[2] gives the new item at position 0 the state from the old item. Always use a stable, unique identifier from your data (database ID, UUID) as the key.