文档地址
入门教程: 认识 React
完整代码
1. /src/App.js
import Game from "./components/Game";
import "./App.css";
function App() {
return (
<div className="App">
<Game></Game>
</div>
);
}
export default App;
2. /src/components/Game/index.css
body {
font: 14px "Century Gothic", Futura, sans-serif;
margin: 20px;
}
ol, ul {
padding-left: 30px;
}
.board-row:after {
clear: both;
content: "";
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
3. /src/components/Game/index.js
import { useState, useMemo } from "react";
import "./index.css";
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
function Square({ value, onClick }) {
return (
<button className="square" onClick={onClick}>
{value}
</button>
);
}
function Board({ squares, onClick }) {
const rowSquares = useMemo(() => {
return [squares.slice(0, 3), squares.slice(3, 6), squares.slice(6)];
}, [squares]);
return (
<div>
{rowSquares.map((row, rowIdx) => (
<div key={rowIdx} className="board-row">
{row.map((item, index) => {
const i = rowIdx * 3 + index;
const row = rowIdx + 1;
const col = index + 1;
return (
<Square
key={index}
value={item}
onClick={() => onClick(i, row, col)}
></Square>
);
})}
</div>
))}
</div>
);
}
function Move({ step, move, onClick }) {
const desc = move ? "Go to move #" + move : "Go to game start";
return (
<li style={{ textAlign: "left" }}>
<button onClick={onClick}>{desc}</button>
{step.row && (
<>
<span style={{ margin: "0 10px" }}>last position: </span>
<span>
row {step.row},col {step.col}
</span>
</>
)}
</li>
);
}
function Game() {
const [history, setHistory] = useState([
{
squares: Array(9).fill(null),
},
]);
const [stepNumber, setStepNumber] = useState(history.length);
const [xIsNext, setXIsNext] = useState(true);
const squares = useMemo(() => {
return history[stepNumber - 1].squares;
}, [history, stepNumber]);
const winner = calculateWinner(squares);
let status;
if (winner) {
status = "Winner: " + winner;
} else {
status = "Next player: " + (xIsNext ? "X" : "O");
}
function handleClick(i, row, col) {
console.log(i, row, col);
const tempSquares = [...squares];
if (tempSquares[i] || winner) {
return;
}
tempSquares[i] = xIsNext ? "O" : "X";
const tempHistory = [
...history,
{
squares: tempSquares,
row,
col,
},
];
setHistory(tempHistory);
setStepNumber(tempHistory.length);
setXIsNext(!xIsNext);
}
function jumpTo(index) {
setStepNumber(index + 1);
setXIsNext(index % 2 === 0);
}
return (
<div className="game">
<div className="game-board">
<Board
squares={squares}
onClick={(i, row, col) => handleClick(i, row, col)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>
{history.map((item, index) => (
<Move
key={index}
step={item}
move={index}
onClick={() => jumpTo(index)}
></Move>
))}
</ol>
</div>
</div>
);
}
export default Game;