反应重设按钮中的井字游戏不起作用

时间:2020-07-05 15:06:16

标签: reactjs tic-tac-toe

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      currentPlayer: false, //false is X, true is O
      message: null,
      gameOver: false,
      grids : {
        '0': null,
        '1': null,
        '2': null,
        '3': null,
        '4': null,
        '5': null,
        '6': null,
        '7': null,
        '8': null
    }
  }
  this.baseState = this.state
   
}
  
  restartGame = () => {
    this.setState(this.baseState);
  }
  
updateGridHandler = (index) => {
  let updatedGrids = {...this.state.grids};
  updatedGrids[index] = this.state.currentPlayer;
  this.setState(prevState => ({currentPlayer: !prevState.currentPlayer,
     grids: updatedGrids}),
     () => {
        this.checkDraw();
        this.checkWin();
       });
}
  
  checkWin = () => {
    const winningCombination = [
      [0, 1, 2],
      [3, 4, 5],
      [6, 7, 8],
      [0, 3, 6],
      [1, 4, 7],
      [2, 5, 8],
      [2, 4, 6],
      [0, 4, 8],
    ];

    for (let i = 0; i < winningCombination.length; i++) {
    const [a, b, c] = winningCombination[i];
    if (this.state.grids[a] && this.state.grids[b] &&
       this.state.grids[c]) {
         console.log('O won');
       }
      else if (this.state.grids[a] === false &&
        this.state.grids[b] === false &&
           this.state.grids[c] === false) {
             console.log('X won');
    }
  }
  }
  
    checkDraw = () => {
    for(let grid in this.state.grids)
            if(this.state.grids[grid] === null) return false; 
  }
  
  render() {
   
    return (
      <div className="App">
             <header className="Header">
          <h1>Tic Tac Toe</h1>
          <Board grids={this.state.grids}
            player={this.state.currentPlayer}
            updateGrid={(index) => this.updateGridHandler(index)}
             />
               <Button reset={this.restartGame}/>
        </header>
      </div>
    );
  }
}

class Board extends React.Component {
    clickHandler = (index, event) => {
      if (this.props.grids[index] === null) {
        //update function callbacks
          this.props.updateGrid(index);

          }
  }
  
  hoverNextPlayer = (index, event) => {
    let classesForCircle = ["Grid", "Circle"];
    let classesForX = ["Grid", "X"];
      if (this.props.grids[index] === null) {        
        if (this.props.player) {
          event.target.className = classesForCircle.join(' ')
         } else {
        event.target.className = classesForX.join(' ') 
         }
      }
    }
  
  stopHoverNextPlayer = (index, event) => {
      if (this.props.grids[index] === null) {
        event.target.className = "Grid";
      }
    }


render() {
  let grids = Object.values(this.props.grids)
  .map((value, index) => <Grid 
                           clicked={(event) => this.clickHandler(index, event)}
                            hovered={(event) => this.hoverNextPlayer(index, event)}
                           stopHovered={(event) => this.stopHoverNextPlayer(index, event)}
                           key={index} value={value}
                           currentPlayer={this.props.player}/>
  );

  return (
    <div className="Board" >
      {grids}
    </div>
);
}

}

const Grid = (props) => {
    return (
      <div 
        onClick={props.clicked}
        className="Grid"
        onMouseOver={props.hovered}
        onMouseLeave={props.stopHovered}>
        {props.value}
      </div>
    );

  }

const Button = (props) => {
  return (
    <div>
      <button onClick={props.reset}>Restart
      </button>

    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('main'));
.App {
  text-align: center;
}

.Header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white
}

.App-link {
  color: #61dafb;
}

.Board {
  padding: 5px;
  margin: auto;
  width: 270px;
  height: 270px;
  display: grid;
  justify-content: center;
  grid-template-columns: repeat(3, auto);
}

:root {
    --grid-size: 90px;
    --grid-content: calc(var(--grid-size) * 0.9);
  }

.Grid {
  box-sizing: border-box;
  width: var(--grid-size);
  height: var(--grid-size);
  border: 1px solid #000;
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
}


.Grid:hover {
  border: 3px solid black;
}

.Grid.X::before,
.Grid.X::after
 {
    position: absolute;
    content: '';
    background-color: lightgrey;
  width: calc(var(--grid-content)*0.1);
  height: var(--grid-content);
}

.Grid.X::before {
    transform: rotate(45deg);
}

.Grid.X::after {
    transform: rotate(-45deg);
}

.Grid.Circle::before,
.Grid.Circle::after {
    position: absolute;
    content: '';
    border-radius: 50%;
}

.Grid.Circle::before {
    width: calc(var(--grid-content)*0.9);
    height: calc(var(--grid-content)*0.9);
    background-color: lightgrey;
}

.Grid.Circle::after {
    width: calc(var(--grid-content)*0.7);
    height: calc(var(--grid-content)*0.7);
    background-color: #282c34;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="main"></div>

我正在制作井字游戏。除重新启动按钮外,其他所有功能均正常运行。 Onclick我将状态重置为初始状态,但是我的网格组件在props更改时没有更新。 它将悬停效果带到我的网格上,以显示下一个玩家在悬停上签名...

当玩家获胜或平局时,将渲染Button组件。 Onclick会将状态设置为初始状态。因此,所有网格都声明:null,但不会更新UI(不会删除类名X或圆形)。在网格组件中,{props.value}也会更新为null。所有网格显示最后一个游戏的最后位置,直到我将鼠标悬停在它们上方或悬停它们为止。这就是我可以将UI清除回空网格的方式。如何获取Grid组件以根据道具更改进行更新?

谢谢!

2 个答案:

答案 0 :(得分:0)

这里出现的问题可能是因为引用复制是在this.baseState = this.state中进行的,而不是按值复制。

因此,每当您尝试使用baseState重置状态时,都不会发生任何变化,因为baseState的最新值为state

尝试一下,按值复制:

this.baseState = {...state}

P.S这仅适用于浅表副本。如果您打算进行深拷贝,请尝试以下What is the most efficient way to deep clone an object in JavaScript?

中的一个选项

答案 1 :(得分:0)

我花了很多时间来弄清楚我们的意思,但这实际上是错误的:

Object.values(this.props.grids)
  .map((value, index) => <Grid value={value}/>
  );

因为我无法映射这样的对象。这是正确的:

Object.keys(this.props.grids)
  .map((gridKey, index) => <Grid value={this.props.grids[gridKey] />

在此位置并在我的Grid组件中添加条件语句

<div className={(props.value === null) ?
    blank : (props.value === true) ?
    classesForCircle.join(' ') : classesForX.join(' ')
  }>...</div>

使用重新启动按钮可以正常工作。