2017-02-27 3 views
0

Als ich das Tutorial in Reaktion auf die Homepage here folgte. Ich wollte den X-O-Code ändern, um in einem Spiel vorwärts und rückwärts zu gehen. Ich füge den folgenden Code ein.reagiert nicht Komponenten mit Änderungen selbst dann, wenn der Zustand sich ändert

Der Verlauf wird in einer Verlaufsliste aufgezeichnet, pos ist der Index der aktuellen Auswahl in der Liste.

Wie Sie sehen können, habe ich drei Tasten: Reset, Up, Down. Wenn Sie auf Reset drücken, setze ich den Status zurück. Wenn du nach oben drückst, erhöhe ich pos. Wenn Sie drücken, verringern Sie die Position. Ich zeige auch pos, um zu überprüfen.

Das Problem ist, dass pos aktualisiert wird, aber die Komponenten werden nicht neu gerendert. für die benutzerfreundlichkeit bin ich einschließlich der heroku here

Was fehlt mir hier?

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; 

Edits:

in handle() geändert

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

zu

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

Ich habe einen Haltepunkt in der Renderfunktion und es wird jedes Mal aufgerufen, wenn auf eine Schaltfläche geklickt wird. – paqash

+0

ok änderte die Frage zu etwas genauer – StarLord

Antwort

1

Ihr Ansatz höchstwahrscheinlich gut funktioniert. Das Problem ist Ihre Geschichte wird

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

führt zur Geschichte [history.length] verweist auf das gleiche Objekt wie die Geschichte [history.length - 1] und so weiter bis zur Geschichte [0]

Versuchen Sie es mit

+0

, dass das Problem gelöst, aber, warum sollte handleClick(), die Klicks auf einzelne Quadrate verknüpft ist beeinflussen, was gerendert werden soll. Um klarer zu sein, wenn ich auf "nach oben" oder "nach unten" klicke, was ist die Abhängigkeit von handleClick(), das ist eine onClick-Methode() – StarLord

+0

, wenn Sie sagen können, was die Bedeutung von slice() dort ist. Es wäre wirklich hilfreich – StarLord

+0

Sie aktualisiert den Komponentenstatus bei handleClick() und Statusänderung ausgelöst neues Rendering. Wenn Sie setState aufrufen, ändern Sie den Status für die gesamte Karte (die entsprechend this.state.history gerendert wird). Das Problem wurde dadurch verursacht, dass das Array mit den gleichen Quadraten geändert wurde, das Sie ursprünglich erhalten haben. Dadurch wurden alle Arrays in der Verlaufssammlung auf die gleiche Instanz verwiesen. Um jedes neue Geschichtsereignis zu einer Kopie des vorherigen Schritts zu machen, habe ich Slice verwendet, um eine flache Kopie zu erhalten – Igor

Verwandte Themen