Capítulo 2 de 116
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.
Square (one cell, a button) → Board (a 3×3 grid of Squares, owns the game state) → Game (wraps Board, owns move history).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.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.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.calculateWinner(squares)) checks the 8 possible winning lines against the current board array — ordinary logic, not a React-specific mechanism.function Square({ value, onSquareClick }) {
return <button className="square" onClick={onSquareClick}>{value}</button>;
}
Square owns no state itself; both its displayed value and its click behavior arrive as props from Board.Squares know nothing about the game — Board (and ultimately Game) owns all the state that needs to be shared or computed across cells.