Capítulo 2 de 116

Chapter 2: Tutorial: Tic-Tac-Toe

Core Idea

Building a small, complete Tic-Tac-Toe game end-to-end is the fastest way to internalize Ch 1's concepts in a realistic context — components, props, state, lifting state up, and (as a bonus) time-travel debugging via storing a history of past states.

Key Concepts

  • Setup: works in the browser sandbox with no local install, or scaffolded locally with a standard React toolchain.
  • Component hierarchy: Square (one cell, a button) → Board (a 3×3 grid of Squares, owns the game state) → Game (wraps Board, owns move history).
  • Lifting state up in practice: each Square starts "dumb" (its own local state), then that state is lifted into the parent Board so a win can be computed across the whole grid and a single click handler can coordinate whose turn it is — the same pattern taught abstractly in Ch 1/Ch 29, now applied to a concrete grid.
  • Immutability pays off directly: the tutorial creates a new copy of the squares array on every move (squares.slice()/spread) rather than mutating in place — this is what makes "time travel" (jumping back to a previous move) trivial, since every past board state is a separate, untouched snapshot kept in an array.
  • Time travel: Game stores a history array of all past board states plus a currentMove index; rendering picks history[currentMove], and a "jump to move" button list re-renders any past board by just changing which history index is selected — no undo/redo logic beyond array indexing.
  • Determining the winner: a plain JavaScript helper function (calculateWinner(squares)) checks the 8 possible winning lines against the current board array — ordinary logic, not a React-specific mechanism.

Code Examples

function Square({ value, onSquareClick }) {
  return <button className="square" onClick={onSquareClick}>{value}</button>;
}
  • What it demonstrates: the "dumb" leaf component pattern — Square owns no state itself; both its displayed value and its click behavior arrive as props from Board.

Key Takeaways

  1. This tutorial is the practical proof of "lift state up": individual Squares know nothing about the game — Board (and ultimately Game) owns all the state that needs to be shared or computed across cells.
  2. Storing history as an array of immutable past states, rather than mutating one board in place, is what makes time-travel debugging nearly free — a direct payoff of the immutability discipline from Ch 25/26.
  3. Win-checking logic is deliberately just plain JS over an array — React doesn't need special support for game logic.

Connects To

  • Ch 1 (Quick Start): every concept exercised here was introduced there in isolation.
  • Ch 29 (Sharing State Between Components): the "lift state up" pattern this tutorial builds around.
  • Ch 26 (Updating Arrays in State): the non-mutating array technique that enables time travel.