Skip to content
nomnivore edited this page Nov 4, 2022 · 30 revisions

Welcome to the React Beginner Training Module

This training module is designed to get you started with React by briefly covering some of the fundamental concepts and then demonstrate how to build a basic TicTacToe application with React. It will also introduce Vite, a front-end toolchain that makes developing with React quick and easy.

Requirements to get started

Training Module Overview

Learning Objectives

  • Create a starter project with Vite
  • Use JSX format to dynamically render HTML
  • Create and use a function component
  • Understand the lifecycle of a component
  • Understand state management using React Hooks

Introduction to React (What is React)

Starting a React Project with Vite

Using JSX to interop JS and HTML

React Components

Common React Hooks

useState

useEffect

useRef

Component Lifecycle

Lab

In this section of the training module we are going to develop a simple TicTacToe application that leverages many of the React concepts that were explained above.

Code snippets provided in this tutorial may contain comments // like this... indicating the location of surrounding code. These comments are purely to help provide context and do not need to be copied into your project.

Getting Started

Start off by downloading our starter files to your local machine, which contain a barebones React/Vite app containing a bit of the boilerplate code and CSS styles for the project.

Open the project in VSCode and open a terminal by clicking Terminal->New Terminal at the top of your screen.

Run the following command in your terminal to install the necessary dependencies:

npm install

If you get an error here, you most likely do not have Node.js properly installed on your machine, or it is out of date.

Next, we'll start a live development server by running the following command so that we can see our changes locally whenever we save:

npm run dev

Creating the board

The basic concept is to store our X and O placement data in an array and use React to convert that into the 3x3 board on the screen.

The first thing we will need to do is create a variable containing our board's current state. To do that, we will use the useState hook to allow this data to persist between renders.

Add the following line at the top inside the App function component in App.jsx:

// function App() {

const [squares, setSquares] = useState(new Array(9).fill(null));

We are going to use a helper function within our App component to create a series of 9 Square components to represent this array. Take note of the Square.jsx file, which contains a nearly empty component, and how we have already imported it in App.jsx using destructuring syntax:

// App.jsx
import { Square } from "./Square";

Add the following function inside the App component:

// const [squares, ...

function renderSquares() {
  const arr = [];

  for (let i = 0; i < squares.length; i++) {
    arr.push(
      <Square
        key={i}
        idx={i}
        value={squares[i]}
      />
    );
  }

  return arr;
}

// return (...

Few things to note here. We are using JSX inside of the arr.push() method, showing that you can utilize JSX elements anywhere within your code. In particular, we have a <Square /> component and are passing a few parameters (properties) with its construction:

  • key: React requires this parameter whenever you have a bunch of components in an array-like structure. We can't access it directly.
  • idx: Because we can't access the key ourselves, we need to set an extra property to track the element's index in the array.
  • value: This will be what the Square renders inside of it on the screen.

Now, lets add this function inside of our App's return statement JSX, in the board div:

<div className="board">
  {renderSquares()}
</div>

Your app should now look something like this:

image

Next we need to add our properties to the Square.jsx and make them display their proper value.

Change the Square component declaration line to look like this:

// Square.jsx
export const Square = ({ idx, value }) => {

Replace the content inside the return statement div with the value property:

// return (
<div className="square">
  {value}
</div>

Checkpoint 1 Snapshot

Adding click functionality and alternating turns

We need another variable to determine which player's turn it is. Just like with our board squares, we are going to use another useState hook with a default value of true.

Add the following lines to the top of your App component:

// const [squares, ...
const [turnX, setTurnX] = useState(true)

We're going to make a function within App handle what happens whenever a square gets clicked, and then pass that function to our Square component.

Let's add the function to our App now:

function squareClicked(idx) {
  setSquares((oldSquares) => {
    const newSquares = [...oldSquares];
    newSquares[idx] = turnX ? "X" : "O";

    return newSquares;
  });

  setTurnX((current) => !current);
}

So what's going on here? We are using the setSquares function to update our squares state variable. Since we want to base the new value off of the old value, we pass in a function, copy the array, modify it based on who's turn it is, and return the new array to be the board's state. Next, we use setTurnX with the same function syntax (the return is implied here because it is one-line) to flip the boolean variable and change turns.

Pass the function as a property to our Square component inside of our renderSquares function by adding this line to our <Square /> JSX:

// arr.push(
  // <Square
  // ...
  handleClick={squareClicked}
// /> ...

In Square.jsx, we need to accept the new property and utilize it in a onClick HTML property in our div. We'll give the onClick property an inline function that only calls handleClick if the square is empty.

Apply these changes by updating the Square.jsx file like this:

// Square.jsx
export const Square = ({ idx, value, handleClick }) => {
  return (
    <div
      className="square"
      onClick={() => (value ? null : handleClick(idx))}
    >
      {value}
    </div>
  );
};

You should now be able to test the functionality of clicking on a square and watching the alternating 'X's and 'O's appear as you click. But how do we know who's turn it is? Let's add a display for that now.

Change the <h2> element in the App return JSX to look like this:

// App.jsx
// <h1 className="title"> ...
<h2>
  Player Turn:
  <span className="turnIndicator">{turnX ? "X" : "O"}</span>
</h2>

Checkpoint 2 Snapshot

Game over!

Clone this wiki locally