Here we will build a tic tac toe in reactjs:
The react tutorial has done a good job explaining react with a tic tac toe, however it does not use hooks. I took another a approach and implement it with hooks which were recently added to the framework.
I hope you enjoy it.
There are three components:
- Square
- Board
- Tic Tac Toe
Square
Square component just receives props to pass to the parent,
these buttons represent the square that the user will interact with.
This is a stateless component since there no state changing through this component.
export function Square({ className, buttonNumber, handleClick }) {
return (
<button type="button" className={className} onClick={handleClick}>
<span>{buttonNumber}</span>
</button>
);
}
Board
The board consists as the name suggests the whole board of the tic tac toe.
This component returns all Square components for the tic tac toe. Also a stateless component.
export function Board({ board, squareClick, isWinner, winners }) {
const SquareType = i => {
const classType = type => {
return `number ${i} ${type}`;
};
let win = winners.some(winner => winner === i);
if (isWinner) {
if (win) {
return classType("winner");
}
}
return classType("lose");
};
return (
<div className="board">
{board.map((number, i) => {
return (
<Square
key={i}
className={SquareType(i)}
buttonNumber={number}
handleClick={() => squareClick(i)}
/>
);
})}
</div>
);
}
Tic Tac Toe
This component is the parent component and uses the useState hook.
The useState hook returns an array with two values in it, the first one is to get the current state and the second one is to set the new state.
Hooks must be declared at the top of the function.
- handleMove : handles user interaction when clicking a button if it is X or O turn.
- handleSquareClick: handles when the user clicks a button and creates a new square to save history.
function TicTacToe() {
let [history, setHistory] = useState([
{
squares: Array(9).fill(null)
}
]);
let [move, setMove] = useState(0);
let [turn, setTurn] = useState(false);
let isNext = turn ? "O" : "X";
let currentSquares = history[move].squares;
let [isWinner, whoWin, winners] = CalculateWinner(currentSquares);
let nturn = <h2 className="turn">Next turn? {isNext}</h2>;
let winner = <h2 className="winner-header"> Winner {whoWin}</h2>;
function handleSquareClick(i) {
let current = history.slice(0, move + 1);
let currentHistory = current[move].squares;
const newArr = [...currentHistory];
newArr[i] = isNext;
setHistory(prevHistory => {
let newHistory = {
squares: newArr
};
return [...current, newHistory];
});
setMove(prevMove => {
return prevMove + 1;
});
setTurn(prev => !prev);
}
function handleMove(i) {
setMove(i);
setTurn(prev => !prev);
}
function handleClear() {
setHistory([{ squares: Array(9).fill(null) }]);
setMove(0);
}
return (
<div className="App">
<header className="AppHeader">
<h1 className="title">TIC TAC TOE </h1>
{isWinner ? winner : nturn}
</header>
<section className="clear-game">
<button className="clear-btn" onClick={handleClear}>
clear game
</button>
</section>
<div className="game">
<div className="steps-moves">
<Board
board={history[move].squares}
squareClick={handleSquareClick}
isWinner={isWinner}
winners={winners}
/>
</div>
<ol>
{history.map((stp, mve) => {
return (
<li key={mve}>
<div className="steps">
<button className="step-btn" onClick={() => handleMove(mve)}>
{" "}
Go to move # {mve}
</button>
</div>
</li>
);
})}
</ol>
</div>
</div>
);
}
source code:
Thank you and enjoy :)
Top comments (0)