如何在单击事件中更改React中的状态?

时间:2017-12-29 00:11:00

标签: javascript reactjs jsx create-react-app

React的新手并使用Create React App创建一个简单的井字游戏,但遇到了以下问题:

  • 点击方块
  • 后,无法让“X”和“O”出现在DOM中
  • currentTurn属性不会改变,并且它始终保持X轮流

在下面的代码中,如果我向console.log(this.state.board)函数添加handleClick()board数组会发生变化,但它都是X。有什么想法吗?

这是我的App.js:

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

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      PLAYER_ONE_SYMBOL: "X",
      PLAYER_TWO_SYMBOL: "O",
      currentTurn: "X",
      board: [
        "", "", "", "", "", "", "", "", ""
      ]
    }
  }

  handleClick(index) {
    var this_board = this.state.board;
    this_board[index] = this.state.currentTurn;
    this.setState = ({
      board: this.state.board,
      currentTurn: this.state.currentTurn === this.state.PLAYER_ONE_SYMBOL ? this.state.PLAYER_TWO_SYMBOL : this.state.PLAYER_ONE_SYMBOL
    })
  }

  render() {
    return (
      <div className="board">
        {this.state.board.map((cell, index) => {
          return <div onClick={() => this.handleClick(index)} className="square">{cell}</div>;
        })}
      </div>
    );
  }
}

我的App.css:

.board {
  display: flex;
  width: 600px;
  height: 600px;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: flex-start;
}

.square {
  display: flex;
  height: 200px;
  width: 200px;
  box-sizing: border-box;
  border: 5px solid black;
  font-size: 5em;
  justify-content: center;
  align-items: center;
}

.square:hover {
  cursor: pointer;
  background-color: #80cd92;
}

编辑:意识到我通过将this.setState视为表达式而不是函数并写入了错误的语法而犯了一个愚蠢的错误。这有效:

this.setState({
  board: this.state.board,
  currentTurn: this.state.currentTurn === this.state.PLAYER_ONE_SYMBOL ? this.state.PLAYER_TWO_SYMBOL : this.state.PLAYER_ONE_SYMBOL
})

1 个答案:

答案 0 :(得分:1)

您的代码几乎没有问题。

  1. 如果您未在render函数中使用该值,则不应保留该状态中的任何值。在您的情况下,您没有在PLAYER_ONE_SYMBOL函数中使用PLAYER_TWO_SYMBOLcurrentTurnrender。因此,您可以将它们定义为组件类的文件或实例变量中的常规变量。

  2. setState是一个功能。您可以通过将状态更改作为对象或函数传递来调用它,该对象或函数将状态更改作为对象返回。请在official documentation

  3. 中详细了解相关信息
  4. 你不应该改变以前的状态。您应该始终根据之前的状态创建新的对象状态,而不要改变它。

  5. 因此,您可以将应用程序组件代码更改为以下内容,以使其正常工作。

    import React, { Component } from "react";
    import { render } from "react-dom";
    import "./App.css";
    
    const PLAYER_ONE_SYMBOL = "X";
    const PLAYER_TWO_SYMBOL = "O";
    
    class App extends Component {
      constructor(props) {
        super(props);
        this.state = {
          board: ["", "", "", "", "", "", "", "", ""]
        };
        this.currentTurn = PLAYER_ONE_SYMBOL;
      }
    
      handleClick(index) {
        this.setState({
          board: this.state.board.map(
            (val, boardIndex) => (boardIndex === index ? this.currentTurn : val)
          )
        });
    
        this.currentTurn =
          this.currentTurn === PLAYER_ONE_SYMBOL
            ? PLAYER_TWO_SYMBOL
            : PLAYER_ONE_SYMBOL;
      }
    
      render() {
        return (
          <div className="board">
            {this.state.board.map((cell, index) => {
              return (
                <div onClick={() => this.handleClick(index)} className="square">
                  {cell}
                </div>
              );
            })}
          </div>
        );
      }
    }
    

    注意我是如何使用setState函数更改状态但没有改变状态。 map函数总是返回一个新数组而不修改/改变原始数组。