Introduction
In this article, I'm going to show how to create a custom React component for a TicTacToe Game interactively in a React Application.
Requirement
- Basic knowledge of React
- Knowledge about useState & useEffect hooks
- Visual Studio Code
Step 1. We need to create a new React app using the below command.
npm create-react-app tic-tac-toe
Step 2. Create a new folder named components and then a new file named TicTacToe.js and add the following code.
import { useEffect, useState } from "react";
import "./styles.css";
function Square({ value, onClick }) {
return (
<button onClick={onClick} className="square">
{value}
</button>
);
}
export default function TicTacToe() {
const [squares, setSquares] = useState(Array(9).fill(""));
const [isXTurn, setIsXTurn] = useState(true);
const [status, setStatus] = useState("");
function getWinner(squares) {
const winningPatterns = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
[0, 3, 6],
[1, 4, 7],
];
for (let i = 0; i < winningPatterns.length; i++) {
const [x, y, z] = winningPatterns[i];
if (
squares[x] &&
squares[x] === squares[y] &&
squares[x] === squares[z]
) {
return squares[x];
}
}
return null;
}
function handleClick(getCurrentSquare) {
let cpySquares = [...squares];
if (getWinner(cpySquares) || cpySquares[getCurrentSquare]) return;
cpySquares[getCurrentSquare] = isXTurn ? "X" : "O";
setIsXTurn(!isXTurn);
setSquares(cpySquares);
}
function handleRestart() {
setIsXTurn(true);
setSquares(Array(9).fill(""));
}
useEffect(() => {
if (!getWinner(squares) && squares.every((item) => item !== "")) {
setStatus(`This is a draw ! Please restart the game`);
} else if (getWinner(squares)) {
setStatus(`Winner is ${getWinner(squares)}. Please restart the game`);
} else {
setStatus(`Next player is ${isXTurn ? "X" : "O"}`);
}
}, [squares, isXTurn]);
console.log(squares);
return (
<div className="tic-tac-toe-container">
<div className="row">
<Square value={squares[0]} onClick={() => handleClick(0)} />
<Square value={squares[1]} onClick={() => handleClick(1)} />
<Square value={squares[2]} onClick={() => handleClick(2)} />
</div>
<div className="row">
<Square value={squares[3]} onClick={() => handleClick(3)} />
<Square value={squares[4]} onClick={() => handleClick(4)} />
<Square value={squares[5]} onClick={() => handleClick(5)} />
</div>
<div className="row">
<Square value={squares[6]} onClick={() => handleClick(6)} />
<Square value={squares[7]} onClick={() => handleClick(7)} />
<Square value={squares[8]} onClick={() => handleClick(8)} />
</div>
<h1>{status}</h1>
<button onClick={handleRestart}>Restart</button>
</div>
);
}
Step 3. Then, create a Styles.css to add the styles for our game.
.tic-tac-toe-container {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 100px;
}
.square {
border: 1px solid red;
float: left;
font-size: 40px;
height: 100px;
padding: 0px;
text-align: center;
width: 100px;
margin-right: -1px;
margin-top: -1px;
cursor: pointer;
}
Now, we need to use the TicTacToe Component in the App.js file by removing the default and using the below code.
import './App.css';
import TicTacToe from './Components/TicTacToe/TicTacToe';
function App() {
return (
<div className="App">
<TicTacToe/>
</div>
);
}
export default App;
Finally, you can run your application, and we can see the image slider locally in our React app.
The explanation of the code is as follows.
- Square: A functional component that renders a button for each square, displaying the current value (X or O) and calling onClick when pressed.
- TicTacToe: The main component that manages the game state (squares, turn, and status), renders the grid, checks for a winner or draw, and allows restarting the game.
- useState: Used to track the squares' values, the current player's turn, and the game's status message.
- getWinner: A function that checks the board for a winning combination by comparing the current squares array with predefined winning patterns.
- handleClick: Updates the clicked square, switches the turn, and prevents changes if the game is won or the square is occupied.
- handleRestart: Resets the game by clearing the squares and setting the first turn to X.
- useEffect: Updates the game status message based on the current board state, detecting a win, draw, or the next player.