用 React18 构建Tic-Tac-Toe(井字棋)游戏

下面是一个完整的 Tic-Tac-Toe(井字棋)游戏的实现,用 React 构建。包括核心逻辑和组件分离,支持两人对战。

1. 初始化 React 项目:

bash 复制代码
npx create-react-app tic-tac-toe
cd tic-tac-toe

2.文件结构

scss 复制代码
src/
├── App.js
├── Board.js
├── Square.js
└── index.js

Step 1: Square.js - 单个方块组件

jsx 复制代码
import React from 'react';

const Square = ({ value, onClick }) => {
  return (
    <button 
      className="square" 
      onClick={onClick} 
      style={{
        width: '60px',
        height: '60px',
        fontSize: '24px',
        cursor: 'pointer'
      }}
    >
      {value}
    </button>
  );
};

export default Square;

Step 2: Board.js - 棋盘组件

jsx 复制代码
import React from 'react';
import Square from './Square';

const Board = ({ squares, onClick }) => {
  const renderSquare = (i) => {
    return <Square value={squares[i]} onClick={() => onClick(i)} />;
  };

  return (
    <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      alignItems: 'center',
    }}>
      <div style={{ display: 'flex' }}>
        {renderSquare(0)}{renderSquare(1)}{renderSquare(2)}
      </div>
      <div style={{ display: 'flex' }}>
        {renderSquare(3)}{renderSquare(4)}{renderSquare(5)}
      </div>
      <div style={{ display: 'flex' }}>
        {renderSquare(6)}{renderSquare(7)}{renderSquare(8)}
      </div>
    </div>
  );
};

export default Board;

Step 3: App.js - 游戏逻辑和主组件

jsx 复制代码
import React, { useState } from 'react';
import Board from './Board';


const App = () => {
  const [squares, setSquares] = useState(Array(9).fill(null));
  const [isXNext, setIsXNext] = useState(true);

  const calculateWinner = (squares) => {
    const lines = [
      [0, 1, 2], [3, 4, 5], [6, 7, 8], // Rows
      [0, 3, 6], [1, 4, 7], [2, 5, 8], // Columns
      [0, 4, 8], [2, 4, 6]            // Diagonals
    ];
    for (let [a, b, c] of lines) {
      if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
        return squares[a];
      }
    }
    return null;
  };

  const winner = calculateWinner(squares);
  const handleClick = (i) => {
    if (squares[i] || winner) return; // Ignore if square is already filled or game is won
    const nextSquares = squares.slice();
    nextSquares[i] = isXNext ? 'X' : 'O';
    setSquares(nextSquares);
    setIsXNext(!isXNext);
  };

  const restartGame = () => {
    setSquares(Array(9).fill(null));
    setIsXNext(true);
  };

  const status = winner ? `Winner: ${winner}` : `Next Player: ${isXNext ? 'X' : 'O'}`;

  return (
    <div style={{ textAlign: 'center', marginTop: '50px' }}>
      <h1>Tic-Tac-Toe</h1>
      <Board squares={squares} onClick={handleClick} />
      <h3>{status}</h3>
      <button onClick={restartGame} style={{ padding: '10px 20px', marginTop: '20px' }}>
        Restart
      </button>
    </div>
  );
};

export default App;

Step 4: index.js - 渲染应用

jsx 复制代码
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

3. 启动应用:

bash 复制代码
npm start

打开浏览器,访问 http://localhost:3000 即可运行。如图所示:

希望这些内容对你有所帮助!如果有任何问题,欢迎随时提问。

相关推荐
神秘的猪头23 分钟前
React 脱围机制(二):重新理解 useEffect——它不是生命周期,而是同步外部系统
react.js
卡布鲁23 分钟前
React useMemo 与 useCallback 完全指南:原理、场景与避坑
前端·react.js
何何____1 小时前
Vue 生命周期详解
前端·javascript
默_笙2 小时前
💫 闭包是个背包:拆解小米前端面试题里的三道"闭包陷阱"
前端·javascript·面试
尾善爱看海5 小时前
《JavaScript 数组操作全攻略:12 类 API + 30 个实战场景 + 20 个避坑指南》
前端·javascript·面试
OpsEye5 小时前
为什么你的 Agent 莫名烧钱?聊聊循环调用的兜底方案
javascript·ai编程
linux_cfan6 小时前
16 · `custom-media-element`:属性拦截与转发
前端·javascript·音视频
右耳朵猫AI6 小时前
Web前端周刊2026W38 | React 19.3 发布、StyleX 深潜、jsdom 30.1 提速
前端·javascript·react.js·typescript·node.js
落魄大学生之流水线上谋生计6 小时前
GreenLife Carbon · OpenHarmony 智慧低碳生态平台
javascript
福兮说7 小时前
用 IndexedDB 存用户的文件,我踩过的五个坑
前端·javascript