DEV Community

loading...
Cover image for Converting My Vanilla JavaScript Project into React

Converting My Vanilla JavaScript Project into React

Jessica
Full Stack Software Engineer
・4 min read

When I first learned React, my mind immediately went to the Super Tic Tac Toe game I built three months ago using Vanilla JavaScript. I thought this project was the perfect candidate to refactor into React because of the potential for reusable components and the use of state for the game logic.

Follow along with the code:
Original Project Repo | Deployed Original Project
React Project Repo | Deployed React Project

Game Rules

If you haven't played Super Tic Tac Toe, it's an advanced version of the original game where there is a tic tac toe grid inside each of the nine squares of the gameboard's exterior grid. Players take turns placing their symbol anywhere in the exterior grid space that corresponds to the interior grid space the previous player selected.
demonstrating how to take turns in the game

demonstrating how to take turns in the game

Components

I began by creating basic React components to match the original HTML, which was a lot of copy and pasted div elements. It was so quick and easy to dynamically render the nine squares of the exterior grid and nine squares of each interior grid using the .map() method on an array with nine elements.

const [extValues, setExtValues] = useState([null, null, null, null, null, null, null, null, null]);

return (
    <div className="Gameboard">
        {
            extValues.map((extValue, extIdx) => (
                    <ExteriorSquare />
            ))
        }
    </div>
);
Enter fullscreen mode Exit fullscreen mode

State

I saved these values in state in order to render what is displayed in the square: an 'X', an 'O', or null to display nothing. Also saved in state is the current player, the exterior grid square the current player can play in, and the game winner. Because these values are saved in state, the components will re-render whenever their value is changed. This replaces the need to manipulate the DOM as I did in the original project.

onClick

In addition to learning React, I also leveled up my JavaScript knowledge since I wrote the original project. In the original, I wrote six (6!!!) separate functions to add or remove click event listeners which provide functionality for the player to place their symbol in the space. In the React version, every interior grid space has the onClick function, but I used ternary logic to determine if there is no winner yet, the space is currently empty, and the exterior grid space is valid (based on where the previous player played). If this expression evaluates to true, the space is clickable, if not, nothing will happen if the player tries to click on an invalid square.

const handleClick = (index) => {
    if (!winner && values[index] === null && currentSquare.includes(extIdx)) {
         // functionality to handle click event
    }
}
Enter fullscreen mode Exit fullscreen mode

Check for Win

I'm a little embarrassed to share the original code I wrote to check for a win because of how repetitive it is! But it got the job done and I couldn't think of a better way to do it at the time. This is just evidence of my growth as a dev.
scrolling through scary, repetitive codescrolling through more scary, repetitive code

scrolling through scary, repetitive code

To be honest, I didn't come up with the new code, I turned to Google for help. But googling when you don't know the answer or to find a better, more efficient solution is a valid and necessary skill as a developer. The code in the GIFs above and the code block below are doing the same thing - checking for three matching values to determine if a player has three in a row and won the square. The two GIFs show checking for a win in the interior grid and in the exterior grid. The code below can check both from one function. Yay for efficiency!

const winningPositions = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6]
];

const checkWin = (squares) => {
    for (let i = 0; i < winningPositions.length; i++) {
        const [a, b, c] = winningPositions[i];
        if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
            return squares[a];
        }
    }
    return null;
}
Enter fullscreen mode Exit fullscreen mode

Styling

The final piece of this refactor project is the styling, which I tried to keep the same between versions. I have since learned about CSS variables and that it's better to use relative sizes instead of sizing with hard coded pixels. In addition to those minor adjustments, I originally coded borders around the interior grids and used DOM manipulation to remove the borders on the 8 squares with outside edges. Because React works with the Virtual DOM, I decided to simplify this approach and just use background colors and grid gaps to display the borders around each square.
Refactored CSS in JS to CSS

comparing CSS in JS to just CSS

That's All... For Now!

Thank you for reading about this refactor! If you're just starting to learn development, I would advise you to build projects however you can with your existing knowledge and you can always level up and refactor in the future. Who knows what kind of improvements I'll be able to make in three months!

Discussion (0)

Forem Open with the Forem app