2017-02-27 11 views
0

私は反応ホームページhereのチュートリアルに従っています。私はx-oのゲームコードをゲームの前後に進めるように修正したかったのです。私は以下のコードを含んでいます。反応しても状態が変わってもコンポーネントが変更されない

履歴は履歴リストに記録され、posはリストの現在の選択のインデックスです。

ご覧のとおり、Reset、Up、Downの3つのボタンがあります。リセットを押すと状態がリセットされます。あなたが押し上げると、私はポジションを上げます。あなたが押し下げると、私はポジションを下げます。私はチェックするポジションも表示しています。

問題は、posが更新されていますが、コンポーネントは再レンダリングされていません。使いやすさのために私はヒーローを含むhere

私はここで何が欠けていますか?

import React, { Component } from 'react'; 
import './App.css'; 


function Square(props){ 
    return (
     <div className="square" onClick={() => props.onClick()}> 
      {props.value} 
     </div> 
    ); 
} 

function calculateWinner(squares){ 
    const winners = [ 
     [0, 1, 2], 
     [3, 4, 5], 
     [6, 7, 8], 
     [0, 4, 8], 
     [2, 4, 6], 
     [0, 3, 6], 
     [1, 4, 7], 
     [2, 5, 8] 
    ]; 
    for(let i = 0; i < winners.length; i++){ 
     const [a, b, c] = winners[i]; 
     if(squares[a] && squares[b] === squares[a] && squares[c] === squares[a]){ 
      return squares[a]; 
     } 
    } 
    return null; 
} 

class Board extends Component{ 
    constructor() { 
     super(); 
     this.state = { 
      history: [Array(9).fill(null)], 
      pos : 0, 
      xIsNext: true 
     } 
    } 

    handleClick(i){ 
     const current = this.state.history[this.state.pos]; 
     if (current[i] || calculateWinner(current)) { 

     } else { 
      const history = this.state.history.slice(); 
      const squares = history[this.state.pos].slice(); 
      squares[i] = this.state.xIsNext ? "X" : "O"; 
      history[this.state.pos + 1] = squares; 
      this.setState({ 
       history: history, 
       pos: this.state.pos + 1, 
       xIsNext: !this.state.xIsNext 
      }); 
     } 
    } 

    clickReset(){ 
     this.setState(
      { 
       history: [Array(9).fill(null)], 
       pos : 0, 
       xIsNext: true 
      } 
     ); 
    } 
    clickUp(){ 
     let pos = this.state.pos; 
     if(pos < this.state.history.length) { 
      pos += 1; 
      this.setState(
       { 
        pos: pos, 
        xIsNext: !this.state.xIsNext 
       } 
      ); 
     } 
    } 
    clickDown(){ 
     let pos = this.state.pos; 
     if(pos > 0) { 
      pos -= 1; 
      this.setState(
       { 
        pos: pos, 
        xIsNext: !this.state.xIsNext 
       } 
      ); 
     } 
    } 
    renderSquare(i){ 
     let current = this.state.history[this.state.pos]; 
     return (
      <Square value={current[i]} onClick={() => this.handleClick(i)}/> 
     ) 
    } 

    render() { 
     let status ; 
     const pos = this.state.pos; 
     const current = this.state.history[pos]; 
     const winnerCal = calculateWinner(current); 
     if (winnerCal){ 
      status = "Winner : " + winnerCal; 
     } else { 
      status = "Next Play : " + (this.state.xIsNext ? "X" : "O"); 
     } 
     return (
      <div className="col"> 

       <div className="row justify-content-center"> 
        <div className="board-row"> 
         {this.renderSquare(0)} 
         {this.renderSquare(1)} 
         {this.renderSquare(2)} 
        </div> 
        <div className="w-100"></div> 
        <div className="board-row"> 
         {this.renderSquare(3)} 
         {this.renderSquare(4)} 
         {this.renderSquare(5)} 
        </div> 
        <div className="w-100"></div> 
        <div className="board-row"> 
         {this.renderSquare(6)} 
         {this.renderSquare(7)} 
         {this.renderSquare(8)} 
        </div> 
       </div> 
       <div className="row justify-content-center"> 
        {status} pos: {pos} 
       </div> 
       <div className="row-fluid"> 
        <button type="button" className="col-md-4 btn btn-warning" onClick={() => this.clickReset()}>Reset</button> 
        <button type="button" className="col-md-4 btn btn-danger" onClick={() => this.clickUp()}>up</button> 
        <button type="button" className="col-md-4 btn btn-info" onClick={() => this.clickDown()}>down</button> 
       </div> 
      </div> 
     ) 
    } 
} 
class App extends Component { 

    renderHeader(){ 
     return (
      <div className="row justify-content-center"> 
       <div className="col"></div> 
       <div className="col"> 
        <h3 className="row justify-content-center"> Lets build a xo game </h3> 
       </div> 
       <div className="col"></div> 
      </div> 
     ) 
    } 

    renderBoard(){ 
     return (
      <div className="row"> 
       <div className="col"></div> 
       <Board className="col"/> 
       <div className="col"></div> 
      </div> 
     ) 
    } 

    render() { 
     return (
      <div className="container"> 
       {this.renderHeader()} 
       {this.renderBoard()} 
      </div> 
     ); 
    } 
} 

export default App; 

編集:handleClickで

は()あなたのアプローチが最も可能性が高いだけでなく機能している

const squares = history[this.state.pos].slice(); 
.. 
history[this.state.pos + 1] = squares; 
+0

私は、レンダリング機能にブレークポイントを置き、ボタンがクリックされるたびに呼び出されます。 – paqash

+0

okは問題を解決したより正確な – StarLord

答えて

1

const squares = history[this.state.pos] 
.. 
history[history.length] = squares; 

を変更しました。ように歴史にダウン[0]

使用してみてください - 問題は、あなたの履歴は、[1 history.length]

const squares = history[this.state.pos]; 
squares[i] = this.state.xIsNext ? "X" : "O"; 
history[history.length] = squares; 

は歴史[history.length]参照に歴史と同じオブジェクトをリードして上書きされますされます

const squares = history[this.state.pos].slice(); 
+0

に質問を変更しましたが、個々の四角にリンクされたclickClick()は何をレンダリングすべきかに影響します。 onClickメソッド() – StarLord

+0

であるhandleClick()への依存性は何ですか?スライス()の重要性について言えば、「上」または「下」をクリックするとより明確になります。本当に役に立ちます – StarLord

+0

handleClick()でコンポーネントの状態を更新し、状態の変更によって新しいレンダリングがトリガされました。 setStateを呼び出すと、ボード全体の状態が変更されます(this.state.historyに従ってレンダリングされます)。 問題は、最初に取得した同じ四角形配列を変更して、履歴コレクションのすべての配列を同じインスタンスにすることによって発生しました。それぞれの新しい履歴イベントを前のステップのコピーにするために、スライスを使用して浅いコピーを取得しました – Igor

関連する問題