首页 > 解决方案 > 在返回中访问状态时反应组件未更新?

问题描述

在这里反应新手..

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

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渲染 9Squares并将回调函数传递给,Square它会更新state.Board

上面的代码工作得很好,当我点击任何一个Squares 时,它的值会更新为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并且单击的 s 的值不会更新。

在我看来,这两种实现之间不应该有任何区别,但显然我遗漏了一些东西。为什么转向this.state.squares[]方法会render破坏功能?

标签: reactjs

解决方案


问题在renderSquare(i).

this.renderSquare(this.state.squares[0]),你传递nullrenderSquare方法。

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

  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)} />;
  }

在代码沙箱中查看此示例。


推荐阅读