Welcome to the React Tic-Tac-Toe web application!
This project is built using React and Vite
, focusing on key React concepts and architecture.
Check out the live demo:
React.Tic-Tac-Toe.mp4
- Interactive Tic-Tac-Toe game
- Highlighting the winning combination
- Player turn indication
- Reset game functionality
- Responsive design
- React - A JavaScript library for building user interfaces
- Vite - A fast build tool and development server
- CSS Modules - For modular and reusable styles
- Components: The app is composed of functional components like
Board
andSquare
. - State Management: The game state is managed using the
useState
hook. - Props: Data is passed between components using props to maintain a unidirectional data flow.
- Hooks: Utilizing React hooks for state and effect management.
- Conditional Rendering: Conditionally rendering elements based on the game state.
When updating state that depends on the previous state, it’s important to use a functional update to ensure you're working with the latest state:
setGameState(prevState => {
// logic to create new state based on prevState
});
In this project, two-way binding is not explicitly used as it's more common in form handling. However, React handles one-way data flow efficiently, where state is passed down and events bubble up.
The Tic-Tac-Toe board is represented as a 2D array (multi-dimensional list):
const board = [
[null, null, null],
[null, null, null],
[null, null, null]
];
State updates are done immutably to ensure predictable state management and rendering:
const newBoard = [...board];
newBoard[row][col] = player;
setBoard(newBoard);
State is lifted up to the Board
component to manage the overall game state and logic, allowing child components to remain stateless and receive data via props.
function Board() {
const [board, setBoard] = useState(initialBoardState);
// pass down state and handlers to Square components
}
Avoiding intersecting state ensures that each piece of state is managed independently, reducing complexity and potential bugs. In this app, the board state and player state are managed separately.
const [board, setBoard] = useState(initialBoardState);
const [currentPlayer, setCurrentPlayer] = useState('X');
Derived state or computed values are used to calculate the game's winner, reducing unnecessary state:
const winner = calculateWinner(board);
Buttons (squares) are disabled once they are clicked or if the game has a winner:
<button disabled={board[row][col] || winner} onClick={() => handleClick(row, col)}>
{board[row][col]}
</button>
The architecture follows a component-based structure. Each part of the application is divided into reusable components:
- Board Component: Manages the state of the game and renders
Square
components. - Square Component: Represents each square in the Tic-Tac-Toe grid.
The state management and interaction logic are encapsulated within these components, ensuring a clear separation of concerns.
react-tic-tac-toe/
├── public/
│ ├── index.html
├── src/
│ ├── components/
│ │ ├── GameBoard.jsx
│ │ ├── GameOver.jsx
│ │ ├── Log.jsx
│ │ ├── Player.jsx
│ ├── App.jsx
│ ├── winning-combination.jsx
│ ├── index.jsx
│ ├── index.css
├── package.json
├── vite.config.js
To get a local copy up and running, follow these steps:
-
Clone the repository:
git clone https://github.com/yourusername/react-tic-tac-toe.git
-
Navigate to the project directory:
cd react-tic-tac-toe
-
Install dependencies:
npm install
-
Start the development server:
npm run dev
-
Open your browser and visit: http://localhost:5173
Tip
Feel free to dive into the code to understand the implementation details. Enjoy playing Tic-Tac-Toe! 🎉😊👩💻
Copyright © Shani Bider, 2024