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.