在返回状态下访问状态时,React组件未更新?

时间:2019-04-22 18:33:53

标签: reactjs

在这里与新手联系。

我正在关注Official React Tutorial。以下代码是本教程本身所示的工作版本:

class Square extends React.Component {

    constructor(props, context) {
        super(props, context);
    }

    render() {
        return (
            <button className="square"
                    onClick={() => this.props.onClick()}>
                {this.props.value}
            </button>
        );
    }
}

class Board extends React.Component {

    constructor(props, context) {
        super(props, context);
        this.state = {
            squares: Array(9).fill(null)
        };
    }

    renderSquare(i) {
        return (
            <Square
                value={this.state.squares[i]}
                onClick={() => this.handleClick(i)}
            />
        );
    }

    render() {
        const status = 'Next player: X';

        return (
            <div>
                <div className="status">{status}</div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
            </div>
        );
    }

    handleClick(i) {
        this.setState(
            () => {
                const squares = this.state.squares.slice();
                squares[i] = 'X';
                this.setState({squares: squares});
            }
        );
    }
}

总结一下,Board呈现9 Squares并将回调函数传递给Square,后者会更新state的{​​{1}}。

上面的代码运行良好,当我单击任何Board时,其值将更新为Square

但是,我在学习本教程后犯了一个错误,并实际上在X中实现了renderrenderSquare方法,如下所示:

BoardComponent

该更改位于renderSquare(i) { return ( <Square value={i} onClick={() => this.handleClick(i)} /> ); } render() { const status = 'Next player: X'; return ( <div> <div className="status">{status}</div> <div className="board-row"> {this.renderSquare(this.state.squares[0])} {this.renderSquare(this.state.squares[1])} {this.renderSquare(this.state.squares[2])} </div> <div className="board-row"> {this.renderSquare(this.state.squares[3])} {this.renderSquare(this.state.squares[4])} {this.renderSquare(this.state.squares[5])} </div> <div className="board-row"> {this.renderSquare(this.state.squares[6])} {this.renderSquare(this.state.squares[7])} {this.renderSquare(this.state.squares[8])} </div> </div> ); } 方法中,以及如何从Board#renderSquare调用它。

此更改破坏了功能,被单击的Board#render的值未更新。

在我看来,这两种实现之间应该没有任何区别,但是显然我缺少了一些东西。为什么将Square移至this.state.squares[]方法会破坏功能?

2 个答案:

答案 0 :(得分:0)

问题在于任何this.state.squares[n]可以是nullX

在您的代码中,您可以这样做:

renderSquare(i) {
    return (
        <Square
            value={i}
            onClick={() => this.handleClick(i)}
        />
    );
}


{this.renderSquare(this.state.squares[n])}

您将(而不是索引)传递给renderSquarei中的renderSquarenullX。意味着handleClick不知道要更改什么,因为它需要索引。

答案 1 :(得分:0)

问题出在renderSquare(i)内。

this.renderSquare(this.state.squares[0])上,您将null传递给renderSquare方法。

为了重新渲染组件,您需要定义一个新的状态,该状态不同于先前的状态,但是:

  handleClick(i) {
    this.setState(() => {
      const squares = [...this.state.squares];
      squares[i] = "X";                      //  <-- i is null
      this.setState(prevState => {
        const newState = { squares: squares };
        console.log(prevState);
        console.log(newState);
        console.log(prevState === newState);  // <-- true so no rerender. 
        return newState;
      });
    });
  }

要解决此问题,请在state.squares中为constructor定义值

  constructor(props, context) {
    super(props, context);
    this.state = {
      squares: [...Array(9)].map((_, i) => i)
    };
  }

  renderSquare(i) {
    return <Square value={i} onClick={() => this.handleClick(i)} />;
  }

codesandbox上查看此示例。