How to create a tic-tac-toe game in React

Tic-tac-toe is a simple game played on a grid with three rows and three columns. Two players take turns marking the grid with “X” and “O.” The way to win the game is to get three marks in a row, either horizontally, vertically, or diagonally. It is a fun and easy game that anyone can play.

canvasAnimation-image
1 of 7

Step-by-step procedure

Here, we will discuss the necessary steps to implement this game in React, which will consist of extra features like a reset button and handling the case where there is a tie in the game.

Creating a React app

In case we haven’t created a React app on our systems, we can execute the commands below, one after the other:

npx create-react-app tic-tac-toe
cd tic-tac-toe

Note: In the place of the tic-tac-toe folder name, we can write a folder name of our choice.

For more information on creating a React app, check out this link!

Initializing the board

Now, we move on to the main parts of the code in the App.js file where we start off initializing the state of the board with nine squares using the board variable and store the state of each player’s turn in the xIsNext variable.

// Initialize state for the game board and player turn
const [board, setBoard] = useState(Array(9).fill(null));
//If xIsNext is true, it will be the turn of the player with the symbol 'X'. Else, it will be the player with the symbol 'O'
const [xIsNext, setXIsNext] = useState(true);
Initializing the board states

Note: By default, the game will start with the player with the symbol “X.” This can be changed to start off the game with the symbol “O.”

Calculating the winner

Next, we make the function that decides the rules of the game and its winner, as shown below:

// Determines if there's a winner based on the current board configuration
function calculateWinner(squares) {
//hardcoding all winning combinations
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
// Checks all possible winning combinations
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a]; // Returns the winning symbol if there's a match
}
}
return null; // Returns null if there's no winner
}
The calculatewinner() function for determining the winner of the game

This function checks the squares array (representing the game board) against all possible winning combinations in the lines constant to determine if there’s a winner. It returns the winning symbol (“X” or “O”). In the case of a tie, the null value is returned.

Handling player clicks

We also make the function that is responsible for ensuring that the square isn’t already filled and that there isn’t a winner yet before updating the board state and toggling to the next player’s turn:

// Handles clicks on the board squares
const handleClick = (index) => {
// Checks if there's a winner or if the square is already filled
if (calculateWinner(board) || board[index]) {
return;
}
// Creates a new board array, updates the clicked square, and toggles the player turn
const newBoard = [...board];
newBoard[index] = xIsNext ? 'X' : 'O';
setBoard(newBoard);
setXIsNext(!xIsNext);
};
Handling clicks of a player having “X” or “O”

A copy of the current game board is created with the newBoard variable using the spread operator ([...board]). It updates the square at the clicked index (newBoard[index]) with the current player’s symbol (“X” or “O”) based on the xIsNext state, resulting in the game board state being updated.

Displaying the game status

Afterward, we write the code for displaying the status of the game on our screens. In other words, we display whether the game has been won by the player having the symbol “X” or “O,” or if the game is tied.

// Calculates if there's a winner based on the current board state
const winner = calculateWinner(board);
// Checks if the game is tied: all squares are filled and there's no winner
const isTied = board.every((square) => square !== null) && !winner;
let status;
//displaying the winning player's symbol
if (winner) {
status = `Winner: ${winner}`;
//displaying the "It's a tie!" message in case of a tie
} else if (isTied) {
status = 'It\'s a tie!';
//switching between players turns if no winner is achieved at a certain point
} else {
status = `Player's turn: ${xIsNext ? 'X' : 'O'}`;
}
If statements to display game status

Rendering the game and adding a reset feature

Finally, we make sure that the game is rendered properly in the React app by rendering each individual square, as well as the whole board, when the players make their moves.

The code to render each tic-tac-toe square is given below:

const renderSquare = (index) => {
return (
<button className="square" onClick={() => handleClick(index)}>
{board[index]}
</button>
);
};
Rendering each board square

Every square button on the game board is generated using the <button> element. Each button shows the value from the board array and is linked to the handleClick function for user interaction.

By taking the index parameter as the input, it inserts the value (“X,” “O,” or null) from the board array at the given index into the button text, dynamically displaying the current state of the square on the game board.

Here is the code to render the entire board where every square at each index is rendered individually:

return (
<div className="game">
<div className="game-board">
<div className="board-row">
{renderSquare(0)}
{renderSquare(1)}
{renderSquare(2)}
</div>
<div className="board-row">
{renderSquare(3)}
{renderSquare(4)}
{renderSquare(5)}
</div>
<div className="board-row">
{renderSquare(6)}
{renderSquare(7)}
{renderSquare(8)}
</div>
</div>
<div className="game-info">
<div>{status}</div>
<button onClick={resetBoard}>Reset Board</button>
</div>
</div>
);
Rendering the entire game board

As mentioned above, we implement a basic function that will reset the game board at any time of the game by setting the elements of the board array to null and reset the game with the turn of player “X.”

const resetBoard = () => {
setBoard(Array(9).fill(null));
setXIsNext(true);
};
Resetting the board

Once all of these code sections are implemented, we are all good to go!

Code

All of the steps explained above can be combined in the App.js file of our React project. See the code below to see the game in action!

Conclusion

This React-based tic-tac-toe game enables players to engage in a classic game of strategy and tactics using efficient state management and UI rendering. The seamless integration of game logic, state updates, and dynamic UI components allows for an intuitive gameplay experience, which React is renowned for.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved