我們希望最頂層的Component(Game)能夠紀錄所有squares的變化,所以把State提升到最頂層。
Game :
1.提升State到本層,並建立History來存放所有squares的變化。
class Game extends React.Component
{
//Step 1:提升State到本層
constructor(props)
{
super(props)
this.state = {
history: [{
squares: Array(9).fill(""),
}],
xIsNext: true
}
}
render()
{
return(
<div className="game">
<div className="game-board">
<Board />
</div>
</div>
)
}
}
Board :
1.移除本層的state。
2.移除本層的handleClick funciton。
3.將this.state更改為this.props(本層state改為父層傳遞)。
class Board extends React.Component
{
//Step 1:移除本層的state。
//Step 2:移除本層的handleClick funciton。
renderSquare(i) {
//Step 3:將this.state更改為this.props
return <Square value={this.props.squares[i]} onClick={() => this.props.handleClick(i)}/>;
}
render()
{
const Winner = calculateWinner(this.state.squares);
let status;
if(Winner)
{
status = "Winner :" + Winner;
}
else
{
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return(
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
<dic>
<button onClick={this.Reset}>ReStart</button>
</dic>
</div>
)
}
}
Game :
1.建立上一步動作。
2.顯示遊戲狀態。
class Game extends React.Component
{
constructor(props)
{
super(props)
this.state = {
history: [{
squares: Array(9).fill(""),
}],
xIsNext: true
}
}
render()
{
const history = this.state.history;
const current = history[history.length - 1]; //Step 1:建立上一步動作
const winner = calculateWinner(current.squares); //Step 2:顯示遊戲狀態
let status;
if(winner)
{
status = 'Winner: ' + winner;
}
else
{
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return(
<div className="game">
<div className="game-board">
<Board />
</div>
</div>
)
}
}
Board : 在Game中已經顯示了遊戲的狀態,便可以將本層的顯示遊戲的狀態功能移除
1.移除顯示遊戲的狀態功能。
class Board extends React.Component
{
renderSquare(i) {
return <Square value={this.props.squares[i]} onClick={() => this.props.handleClick(i)}/>;
}
render()
{
//Step 1:移除顯示遊戲的狀態功能
return(
<div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
)
}
}
Game :
1.將handleClick function從 Board component 移到 Game component
2.將squares與handleClick function透過props傳遞給子層
class Game extends React.Component
{
constructor(props)
{
super(props)
this.state = {
history: [{
squares: Array(9).fill(""),
}],
xIsNext: true
}
}
//Step 1:新增handleClick function
handleClick = (i) => {
const history = this.state.history;
const current = history[history.length - 1];
const squares = current.squares.slice();
if (calculateWinner(squares) || squares[i])
{
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{
squares: squares,
}]),
xIsNext: !this.state.xIsNext,
});
};
render()
{
const history = this.state.history;
const current = history[history.length - 1];
const winner = calculateWinner(current.squares);
let status;
if(winner)
{
status = 'Winner: ' + winner;
}
else
{
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return(
<div className="game">
<div className="game-board">
//Step 2:將squares與handleClick function透過props傳遞給子層
<Board
squares={current.squares}
onClick={(i) => {this.handleClick(i)}}
/>
</div>
</div>
)
}
}
Game :
1.新增一個function來判斷是否有下一步動作(以改變button的文字)並選染到一個button中。
2.新增按鈕被點擊後所觸發的funciton(JumpTo)。
3.修改render中選取最後一個動作,根據stepNumber來選取動作。
class Game extends React.Component
{
constructor(props)
{
super(props)
this.state = {
history: [{
squares: Array(9).fill(""),
}],
//Step 2-1:在State中新增一個stepNumber來計算步數。
stepNumber: 0,
xIsNext: true
}
}
handleClick = (i) => {
const history = this.state.history;
const current = history[history.length - 1];
const squares = current.squares.slice();
if (calculateWinner(squares) || squares[i])
{
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{
squares: squares,
}]),
xIsNext: !this.state.xIsNext,
});
};
//Step 2:新增onclick function
jumpTo = (move) => {
this.setState({
stepNumber : move, //Step 2-2:更新stepNumber狀態
//Step 2-3:檢測目前步數是否為偶數(判斷下一步為"X"(偶數)還是"O"(基數))
xIsNext : (move % 2) === 0
});
};
render()
{
const history = this.state.history;
//Step 3:根據stepNumber來選取動作
const current = history[this.state.stepNumber];
const winner = calculateWinner(current.squares);
//Step 1:判斷是否有下一步,並將結果選染到button中
const moves = history.map((step, move) => {
const desc = move ?
'Go to move #' + move :
'Go to game start';
return (
<li key={move}>
<button onClick={() => this.jumpTo(move)}>{desc}</button>
</li>
);
});
let status;
if(winner)
{
status = 'Winner: ' + winner;
}
else
{
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return(
<div className="game">
<div className="game-board">
<Board
squares={current.squares}
onClick={(i) => {this.handleClick(i)}}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{moves}</ol>
</div>
</div>
)
}
}
參考資料 :
React學習指南