【问题标题】:Render called before setState updates state在 setState 更新状态之前调用渲染
【发布时间】:2019-08-04 22:16:54
【问题描述】:

有什么方法可以确保在setState 实际更新状态之后调用render?据我所知,setState 是异步的。我尝试将render 作为setState 的回调,但它仍然会在状态更新之前呈现。

HTML 代码:

<div id="root"></div>

反应代码:

class Table extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            squares: []
        };
        this.create = this.create.bind(this);
    }

    create() {
        console.log('squares before: ' + this.state.squares);
        var a = [];
        for (var i = 0; i < 16; i++) {
            a.push(undefined);
        }
        i = Math.floor(Math.random() * 8);
        a[i] = 2;
        i = Math.floor(Math.random() * 8) + 8;
        a[i] = 2;
        console.log('new squares: ' + squares);
        console.log('non-updated squares: ' + this.state.squares);
        this.setState({
            squares: a
        }, console.log('updated squares: ' + this.state.squares);
    }

    componentWillMount() {
        this.create();
    }

    render() {
        console.log('rendering');
        return (<div>
                <table className="table">
                    <tbody>
                        <tr>
                            <td className="td"><Number number={this.state.squares[0]}/></td>
                            <td className="td"><Number number={this.state.squares[1]}/></td>
                            <td className="td"><Number number={this.state.squares[2]}/></td>
                            <td className="td"><Number number={this.state.squares[3]}/></td>
                        </tr>
                        <tr>
                            <td className="td"><Number number={this.state.squares[4]}/></td>
                            <td className="td"><Number number={this.state.squares[5]}/></td>
                            <td className="td"><Number number={this.state.squares[6]}/></td>
                            <td className="td"><Number number={this.state.squares[7]}/></td>
                        </tr>
                        <tr>
                            <td className="td"><Number number={this.state.squares[8]}/></td>
                            <td className="td"><Number number={this.state.squares[9]}/></td>
                            <td className="td"><Number number={this.state.squares[10]}/></td>
                            <td className="td"><Number number={this.state.squares[11]}/></td>
                        </tr>
                        <tr>
                            <td className="td"><Number number={this.state.squares[12]}/></td>
                            <td className="td"><Number number={this.state.squares[13]}/></td>
                            <td className="td"><Number number={this.state.squares[14]}/></td>
                            <td className="td"><Number number={this.state.squares[15]}/></td>
                        </tr>
                    </tbody>
                </table>
            </div>);
    }
}

class Game extends React.Component {
    newGame() {
        this.refs.table.create();
    }

    render() {
        return (<div>
            <Table ref="table"/>
            <button id="newGame" onClick={this.newGame.bind(this)}>New Game</button>
        </div>);
    }
}

基本上,这里发生的事情是首先记录“渲染”,然后是“更新方块:...”,如下所示:

squares before: [undefined, 2, undefined, undefined, undefined, 2]
new squares: [undefined, undefined, 2, undefined, 2, undefined]
non-updated squares: [undefined, 2, undefined, undefined, undefined, 2]
rendering
updated squares: [undefined, undefined, 2, undefined, 2, undefined]

我尝试对setStaterender进行回调,但第二次渲染将在第一次渲染之后但在setState更新state之前渲染:

this.setState({
  squares: a
}, this.render);

它记录了:

squares before: [undefined, 2, undefined, undefined, undefined, 2]
new squares: [undefined, undefined, 2, undefined, 2, undefined]
non-updated squares: [undefined, 2, undefined, undefined, undefined, 2]
rendering
rendering

任何帮助将不胜感激。提前致谢!

【问题讨论】:

    标签: javascript reactjs setstate asynchronous-javascript


    【解决方案1】:

    componentWillMount 中的synchronous setState 不会触发重新渲染,而是反映初始渲染本身的变化。然而,setState 的回调是在渲染方法之后调用的。

    如果您在渲染方法中记录state squares,它将在初始渲染本身中记录正确的结果。

    P.S. componentWillMount 在最新版本中已弃用,最好将当前逻辑放在构造函数中,而不是 componentWillMount

    Working demo

    【讨论】:

    • 但是如何修复代码以便在调用 setState 后呈现?
    • @VapporWashmade,你现在的代码只有在调用setState并更新状态后才会调用render,之后只会触发setState的回调
    • @ShubhamKhatri 我也有类似的问题。有没有前提条件,render 方法只有在状态真正改变后才会被调用。
    【解决方案2】:

    使用shouldComponentUpdate(object nextProps, object nextState),进行渲染,每次返回true,都会进行渲染

    【讨论】:

      猜你喜欢
      • 2018-05-27
      • 2017-09-16
      • 1970-01-01
      • 2018-02-27
      • 1970-01-01
      • 2021-01-18
      • 2017-02-07
      • 2019-08-09
      • 1970-01-01
      相关资源
      最近更新 更多