DEV Community

add_early
add_early

Posted on

React Explained Through a Tic-Tac-Toe Build

What Is React?

React is a library for building user interfaces.

It runs in the browser as a Single Page Application (SPA), but it’s often used as part of a full-stack setup where it communicates with a server or API.

It’s sometimes referred to as a framework because it’s powerful and comparable to Angular or Vue—but technically, React focuses on the view layer.

Key facts:

  • Created and maintained by Facebook
  • Runs in the browser
  • Compiles into a JavaScript bundle loaded once
  • Handles routing and updates client-side
  • Commonly paired with backend frameworks like Django

How React Works

A React app is typically a single HTML page.

React:

  • mounts into a root <div>
  • manages routing internally
  • updates only the parts of the UI that change
  • communicates with the server using JSON

From React, you can:

  • GET data
  • ADD data
  • UPDATE data
  • DELETE data

React doesn’t include routing out of the box—most projects use react-router-dom.


React in the MVC Model

In an MVC architecture:

  • Model → data
  • View → UI
  • Controller → routing & requests

React acts as the View.

Instead of separating logic and markup, React uses JSX, which allows JavaScript and markup to live together in a readable way.


Virtual DOM & One-Way Data Flow

React uses a Virtual DOM, allowing it to:

  • update parts of the page without full reloads
  • remain fast and responsive

Data flows one way:

  • state → UI
  • UI events → state updates

State is immutable—you don’t change it directly.

You replace it using functions like setState() or useState().

This makes:

  • debugging easier
  • performance more predictable

Prerequisites Before Learning React

You should be comfortable with:

  • JavaScript fundamentals
  • variables, functions, arrays, objects
  • async/await & Promises
  • array methods like .map() and .forEach()
  • Fetch API & HTTP concepts

React isn’t hard—but it assumes JavaScript fluency.


Components in React

React UIs are built from components.

Modern React primarily uses function components with Hooks.

Class components still exist, but they’re now considered legacy.

Components:

  • are reusable
  • manage their own state
  • compose together like puzzle pieces

Working With State

State controls how components behave and render.

Common types:

  • Local state → belongs to one component
  • Global state → shared across components

State is always updated immutably.


React Hooks (Overview)

Common hooks:

  • useState → manage state
  • useEffect → handle side effects

Advanced hooks:

  • useContext
  • useReducer
  • useRef

Creating a React App

Two common approaches:


bash
npx create-react-app my-app

or with Vite:

npx create-vite@latest my-app -- --template react


Both provide:

a preconfigured dev environment

React + tooling

a structured project layout

Basic File Structure

public/index.html → mounts the app via <div id="root"></div>

src/index.js → entry point

App.js → root component

JSX must return a single root element (or use fragments <> </>).

JSX vs Jinja

Both mix logic with markup:

JSX runs client-side

Jinja runs server-side

They solve similar problems at different layers.

Props & Component Communication

Props are passed from parent to child.

You can:

pass individual values

destructure props

pass functions for event handling

Props make components reusable and predictable.

Styling in React

Common options:

inline styles

external CSS files

reusable styled components

Remember:

use className, not class

Lists, Keys, and Immutability

When rendering lists:

each item needs a unique key

state updates must be immutable

Instead of mutating arrays:

setItems([...items, newItem])

Global State Options

For shared state:

Context API

Redux

other state managers

Choose based on complexity—not hype.

Production Builds

To build for production:

npm run build


This:

bundles JavaScript

minifies assets

removes development-only code

outputs optimized files into /build

That folder is what gets deployed.

Applying These Concepts: Building Tic-Tac-Toe
Multidimensional Arrays in JavaScript

A Tic-Tac-Toe board is a 3×3 grid, represented as an array of arrays.

This structure works well for:

Tic-Tac-Toe boards

Chess boards

Seating charts

Tables of data

Maps

Each sub-array is a row. Each item is a cell.

Managing Game State with Immutability

Objects and arrays are reference values in JavaScript.

You should never mutate them directly.

Instead:

create a copy

update the copy

replace the state

React only re-renders when it sees a new reference.

Lifting State Up

Lifting state up means moving shared state to the closest common parent.

You do this when:

multiple components need the same data

one updates the state and another reads it

This keeps everything in sync.

Lifting State in Tic-Tac-Toe

In this project:

<GameBoard /> renders the grid

<Player /> shows whose turn it is

Both need to know the active player.

Solution

Keep activePlayer in <App /> and pass it down as props.

Key ideas:

state lives in the parent

children receive it via props

children request updates via callbacks

Avoiding Intersecting State

Intersecting state happens when the same data exists in multiple places.

This causes:

unpredictable behavior

debugging headaches

Best practice:

keep a single source of truth

derive state when possible

Deriving State Instead of Storing It

The game board itself does not use useState.

Instead:

it receives turns as props

it replays those turns to reconstruct the board

This makes the board:

stateless

predictable

easier to reason about

Determining the Winner

Each cell is accessed using:

board[row][col]


There are 8 winning combinations:

3 rows

3 columns

2 diagonals

Loop through each and check if all three cells match.

JSX Fragment Gotcha

This causes an error:

{winner && <GameOver /><p>Winner: {winner}</p>}


JSX expressions must return one parent element.

Wrap them in a fragment or container to fix it.

Two Ways to Create the Board

Dynamic:

Array(3).fill(null).map(() => Array(3).fill(null))


Static:

[
  [null, null, null],
  [null, null, null],
  [null, null, null]
]


Both work—just understand reference behavior.

Why Immutability Matters

Mutation:

arr.push(4)


❌ Same reference → React may not re-render

Immutable update:

const newArr = [...arr, 4]


✅ New reference → React updates correctly

A Personal Reflection

I compared myself to someone finishing a FastAPI course in under a day while I struggled through React.

That comparison hurt.

But React demands a new way of thinking:

JavaScript is weirder than Python

frontend is messier

state management changes how you reason

And Tic-Tac-Toe?
It’s deceptively complex.

Finishing the Game

I finished it.

And more importantly:

I understand React better

I understand my limits better

I understand my growth better

A simple 3×3 grid taught me a lot.

Final Thoughts

React doesn’t carry you—you carry it.

And that’s what makes learning it valuable.

On to the next.


Enter fullscreen mode Exit fullscreen mode

Top comments (0)