Reactのチュートリアル(三目並べ)を終わらせて追加課題の1つ目をやっています。
1.履歴内のそれぞれの着手の位置を (col, row) というフォーマットで表示する。
座標を表示させるために2次元配列にして座標の表示機能はなんとか実装できました。
しかし、チュートリアル終了時点ではできていたはずの過去の盤面に戻る機能が壊れてしまいました。
propのhistory(履歴)の中身を見てみると1手目〜最新手まですべて最新のsquares(盤面)になっていました。
handleClick内のsetStateがうまく出来ていないのだと思います。(74行目あたり)
sliceで複製できるのは1次元配列だけという記事も見ました。
それでもsliceしないと戻った後に別の手を実行した際の矛盾が解決できないと思います。
2次元配列を使わないようにすればできるかもしれませんが、2次元配列を使って出来るようにしたいです。
javascript
1import React from 'react'; 2import ReactDOM from 'react-dom'; 3import './index.css'; 4 5function Square(props) { 6 return ( 7 <button className="square" onClick={props.onClick}> 8 {props.value} 9 </button> 10 ); 11} 12 13class Board extends React.Component { 14 renderSquare(col, row) { 15 return ( 16 <Square 17 value={this.props.squares[col][row]} 18 onClick={() => this.props.onClick(col, row)} 19 /> 20 ) 21 } 22 render() { 23 return ( 24 <div> 25 <div className="board-row"> 26 {this.renderSquare(0, 0)} 27 {this.renderSquare(0, 1)} 28 {this.renderSquare(0, 2)} 29 </div> 30 <div className="board-row"> 31 {this.renderSquare(1, 0)} 32 {this.renderSquare(1, 1)} 33 {this.renderSquare(1, 2)} 34 </div> 35 <div className="board-row"> 36 {this.renderSquare(2, 0)} 37 {this.renderSquare(2, 1)} 38 {this.renderSquare(2, 2)} 39 </div> 40 </div> 41 ); 42 } 43} 44 45class Game extends React.Component { 46 constructor(props) { 47 super(props); 48 var squares = new Array(3); 49 for (let y = 0; y < 3; y++) { 50 squares[y] = new Array(3).fill(null); 51 } 52 this.state = { 53 history: [{ 54 squares: squares, 55 coordinate: { 56 col: null, 57 row: null, 58 } 59 }], 60 stepNumber: 0, 61 xIsNext: true, 62 } 63 } 64 65 handleClick(col, row) { 66 const history = this.state.history.slice(0, this.state.stepNumber + 1); 67 const current = history[history.length - 1]; 68 const squares = current.squares.slice(); 69 if (calculateWinner(squares) || squares[col][row]) { 70 return; 71 } 72 squares[col][row] = this.state.xIsNext ? 'X' : 'O'; 73 74 this.setState({ 75 history: history.concat({ 76 squares: squares, 77 coordinate: { 78 col: col, 79 row: row, 80 } 81 }), 82 stepNumber: history.length, 83 xIsNext: !this.state.xIsNext, 84 }); 85 } 86 87 jumpTo(step) { 88 this.setState({ 89 stepNumber: step, 90 xIsNext: (step % 2) === 0, 91 }) 92 } 93 94 render() { 95 const history = this.state.history; 96 const current = history[this.state.stepNumber]; 97 const winner = calculateWinner(current.squares); 98 99 const moves = history.map((step, move) => { 100 const desc = move ? 101 'Go to move #' + move + ' (' + step.coordinate.col + ',' + step.coordinate.row + ')' : 102 'Go to game start'; 103 return ( 104 <li key={move}> 105 <button onClick={() => this.jumpTo(move)}>{desc}</button> 106 </li> 107 ); 108 }); 109 110 let status; 111 if (winner) { 112 status = "Winner: " + winner; 113 } else { 114 status = "Next player: " + (this.state.xIsNext ? "X" : "O"); 115 } 116 117 return ( 118 <div className="game"> 119 stepNumber:{this.state.stepNumber} 120 <div className="game-board"> 121 <Board 122 squares={current.squares} 123 onClick={(col, row) => this.handleClick(col, row)} 124 /> 125 </div> 126 <div className="game-info"> 127 <div>{status}</div> 128 <ol>{moves}</ol> 129 </div> 130 </div> 131 ); 132 } 133} 134ReactDOM.render( 135 <Game />, 136 document.getElementById('root') 137); 138function calculateWinner(squares) { 139 for (let x = 0; x < 3; x++) { 140 if (squares[x][0] && squares[x][0] === squares[x][1] && squares[x][0] === squares[x][2]) { 141 return squares[x][0]; 142 } 143 } 144 for (let y = 0; y < 3; y++) { 145 if (squares[0][y] && squares[0][y] === squares[1][y] && squares[0][y] === squares[2][y]) { 146 return squares[0][y]; 147 } 148 } 149 if (squares[0][0] && squares[0][0] === squares[1][1] && squares[0][0] === squares[2][2]) { 150 return squares[0][0]; 151 } 152 if (squares[0][2] && squares[0][2] === squares[1][1] && squares[0][2] === squares[2][0]) { 153 return squares[0][2]; 154 } 155 return null; 156}
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/03/26 02:05
2020/03/26 02:14