How To Make A Fantastic Tic Tac Toe Game With React

by kleamerkuri
Tic tac toe game with react.

Are you ready to level up your coding skills and create an unforgettable gaming experience?

In this tutorial, we’re diving deep into the world of React.js development to build a Tic Tac Toe game that’s computer vs player.

We’ll be taking our already nifty state management to a whole other level while creating something portfolio-worthy!

Related: How To Make A Really Good Shopping Cart With React

Not that all our other projects don’t deserve some portfolio limelight. If anything, every single THT project will make your skills shine bright like a diamond 💎

It’s just that Tic Tac Toe is a classic developer test. The logical workflow it requires is a perfect way to gauge our ability to craft programming logic.

For all my coding girl gurus out there, it’s the “no-makeup” makeup look of the programming world 😉

For anyone like DM who doesn’t understand a word of that, think about the difficulty of making something simple. The skill it requires. The workarounds it demands.

Hey!
Checkout the live demo here! Design inspo drawn from Crypto Wallet App I Ofspace on dribbble.

No more talking, get ready to unleash your creativity and take your gaming prowess to new heights!

start game screen

Beginning the adventure with a start page

Picture this: You’re greeted by a sleek start page that sets the stage for an epic gaming journey.

The start page consists of an app title, logo, and action button that initializes gameplay.

Tic tac toe react start screen.

With its captivating design and intuitive interface, you can’t help but feel a surge of excitement as you hit that Start button.

I use box-shadow to create a background color slide visual effect.

.Btn-active:hover {
    box-shadow: inset 400px 0 0 0 var(--lightblue-tint);
}

The inset keyword specifies that the shadow should be inset inside the element, creating an inner shadow rather than an outer shadow, extending the stated 400px.

Note that usually, I call instance-specific styles added on a custom component className. However, doing so won’t work in this case because we’re spreading the props other than className, {...props}.

So any className prop will overwrite the default button styles that should apply to the Button component. To avoid the overwrite, we need to rename the instance styles which I call cs (clearly creative 🙄).

I, also, use React PropTypes to define the display style of the button as either active or regular.

Button.propTypes = {
    active: PropTypes.bool.isRequired
}
first and second selection screens

Setting up the selection screens

Customize a user’s gaming experience through personalization!

The selection screens guide users to choose a game symbol and display name, both required. If a user tries to move to the next screen without making a selection, an error alert will appear.

However, I’m not super rigid, I provide the option to navigate among the selections screens so a user can always go back to change the symbol or display name before gameplay.

From the name selection screen, you can go back to the symbol selection screen (the first screen).

Symbol selection screen.

Tip: Casually remind a user what symbol they chose on name selection for improved user experience!

On the game-on screen, there’s the option to back to name selection to change your name. Here, again, the user can see their selection of the prior screen through the displaying content.

Name selection screen.

Hint: The computer name is dynamically chosen, the user has nothing to do on their end.

third selection screen

There’s, also, the option to go back to the start page by exiting the selection screens altogether from any screen. A full navigation experience is going on despite the simplicity of these screens!

Pre-game screen.

Game Screen

game board screen

Finally, the game screen where we’re presented with the gaming board and all of the game action.

Initial game screen.

First, notice how the click of “Game On” on the last selection screen smoothly guides directly to the game board. Here I employ the useRef and useEffect hooks to scroll into view the game board.

It all comes down to:

useEffect( ()=>{
        navWrapRef.current.scrollIntoView({ behavior: 'smooth' });
    }, [startGame]);

Second, note the game nav. This is separate from the board itself and it provides that crucial navigation component for the user to (a) reset the game board by clearing out any existing gameplay OR (b) end the game and be redirected to the start page.

game over screen
Game over screen.
Rematch resets the board.
Start over screen.
Scoreboard display when done with the game.

There’s a lot of state management. Any sort of game will require lots of dexterity when it comes to managing the states of a variety of variables other than the gameplay itself.

Since this is a relatively low-impact game, I opt to use useContext to manage the states.

For more useContext see How To Build A Really Stunning Quote App With React.

const GameContext = createContext({
    isGameOn: false,
    setIsGameOn: () => { },
    players: {},
    setPlayers: () => { },
    showBoard: false,
    setShowBoard: () => { },
    startGame: false,
    setStartGame: () => { },
    resetBoard: false,
    setResetBoard: () => { }
});

I use useContext in conjunction with useState for cases like managing the endGame state to display the scoreboard.

Time to show your skills with gameplay

Ready to play? Let’s begin by setting up the game board which displays the players’ info, like their names and symbols, along the Tic Tac Toe grid.

Who goes first is determined randomly by the system and a turn is indicated above the game board. An active player is outlined when taking a turn.

Game board players.

Most of the core game logic rests in the computerMove function. The code creates an array (emptyCells) that contains the indices of all empty cells in the currentBoard array. It uses the reduce() method to iterate over the currentBoard array, pushing the index of each empty cell to the accumulator array if the cell is empty. Finally, it returns the accumulator array containing the indices of all empty cells.

const emptyCells = currentBoard.reduce((acc, cell, index) => {
      if (!cell) acc.push(index);
      return acc;
    }, []);

Tip 👇

We’re checking if !cell is true, which means the cell is falsy (either null, undefined, 0, '', false, or NaN).

Now, computerMove takes a copy of the board. By using the spread operator [...board], we create a new array with the same elements as board, ensuring that the computerMove function always receives the most up-to-date version of the board state.

However, note that in the checkWinner function, we don’t need to create a copy of the board using [...board] because we’re only reading the board state and not modifying it. Therefore, we can directly pass board to the checkWinner function.

Moving on, let’s take a look at the behind-the-scenes of the reset/rematch logic.

const resetGameBoard = useCallback(() => {
        // console.log('Resetting board...');
        setResetBoard(false);
        resetGame();
    }, []);

I’m using the useCallback hook in tandem with useEffect to ensure the resetGame callback is only triggered when the resetBoard flag is set to true.

useEffect(() => {
        // console.log('Running reset')
        if (resetBoard) {
            resetGameBoard();
            setIsCellActive(false);
            cell.forEach(item=>item.classList.remove(s.active));
            setCell([]);
        } else {
            return;
        }

    }, [resetBoard, resetGameBoard]);

When only using useEffect, the state change of resetBoard, regardless of true or false, triggers a component re-render resulting in a “glitch”.

In using useCallback, I memoize the resetGame function and use the useEffect to trigger the reset logic only when the reset state changes to true.

As said previously, gameplay involves lots of logic and state management which is to be expected considering it’s what makes a game a game 💁‍♀️

It’s a wrap

And there you have it, fellow THT mates, one futuristic Tic Tac Toe game with React.js is done! Honestly, building a game is the best way to thoroughly put your state management skills to the test.

As a quick overview, in this tutorial, we built a Tic Tac Toe game that’s computer vs player with React.js. The project consists of a start page, selection screens (for player info), and a game screen. On the game screen, we have:

  • a navigation bar with reset and done action buttons
  • display of player and gameplay status
  • the game board with keyboard navigation enabled

It’s a simple game with plenty of challenges for any developer. The result? An awesome game you can share and showcase.

All source code is available on GitHub. See ya on the next one 🕶️

Related Posts