当给组件状态赋值时,为什么console.log会打印出先前的状态?

19

我从“数字组件”向“主组件”发送数值。一切都很顺利,直到我将该值设置为该组件的状态。

var Numbers = React.createClass({
    handleClick: function(number){
        this.props.num(number)
    },
    render: function(){
        return (
            <div>
                <button onClick={this.handleClick.bind(null, 1)}>1</button>
                <button onClick={this.handleClick.bind(null, 2)}>2</button>
                <button onClick={this.handleClick.bind(null, 3)}>3</button>
            </div>
        )
    }
})

var Main = React.createClass({
    getInitialState: function(){
        return {
            number: 0
        }
    },
    handleCallback: function(num){
        console.log("number is right here: " + num);
        this.setState({
            number: num
        })
        console.log("but wrong here (previous number): " + this.state.number)
    },
    render: function() {
        return (
            <Numbers num={this.handleCallback} />
            //<SomeComponent number={this.state.number} />
        )
    }
});

React.render(<Main />, document.getElementById('container'));

为什么它会表现成这样?handleCallback函数中的第二个console.log打印了先前的数字,而不是在num参数中的数字。我需要正确的数字在我的状态中,因为我将立即将其作为属性发送到我的SomeComponent组件。

https://jsfiddle.net/69z2wepo/13000/

5个回答

32

根据文档

setState() 不会立即改变 this.state,而是创建了一个待处理的状态转换。在调用此方法后访问 this.state 可能会返回现有值。调用 setState 的同步操作没有保证,并且调用可能会批处理以获得性能上的收益。

如果想在调用 setState 后打印更改,请使用可选的回调参数:

this.setState({
    number: num
}, function () {
    console.log(this.state.number);
});

你会如何解决 SomeComponent 的问题?我现在知道它为什么不起作用,但我不知道如何在仅当 this.state 已更新时将状态作为 props 传递。我能否以某种方式将 <SomeComponent number={this.state.number} /> 包装到回调函数或其他东西中? - StrangeManInMask
改变组件的状态或属性会强制重新渲染,除非您已经实现了 shouldComponentUpdate 来告诉它不要这样做。因此,一旦在 <Main/> 中更改了状态,它将重新渲染,并将新数字作为新属性传递给 <SomeComponent/>。如果您在 <SomeComponent/> 中实现了 componentWillReceiveProps,则会在接收到的属性中看到该数字。这有意义吗?还是您希望我修改我的答案并深入一点? - Michael Parker
如果您有时间/兴趣,可以深入了解。我会非常感激。我的问题是<SomeComponent/>不等待<Main/>重新渲染(我认为..),因此无法发送状态的正确值。我不知道如何实现您展示的回调函数。也许这可以更好地解释:https://jsfiddle.net/69z2wepo/13007/ - StrangeManInMask
你的问题在于你正在警报<SomeComponent/>中的当前props而不是新的props。函数componentWillReceiveProps可以接受一个参数nextProps,其中包含所有接收到的新props。这是修复后的版本:https://jsfiddle.net/69z2wepo/13008/。只需记住,在`componentWillReceiveProps`执行完成之前,`this.props`不会改变。 - Michael Parker

3

setState 方法是异步的,因此在 console.log 调用时新状态还没有到达。您可以将回调函数作为第二个参数传递给 setState,并在其中调用 console.log。在这种情况下,值将是正确的。


1
也许是因为在新的状态真正设置之前,控制台日志就被触发了。
您应该使用以下功能:
componentDidUpdate: function() {
    console.log(this.state.number);
}

每次状态更新时,都会触发此函数。
希望能对您有所帮助。

0

0

为了在控制台中打印状态编号,请使用

this.setState({
        number: num
    },function(){console.log("but wrong here (previous number): " + this.state.number)})

而不是

this.setState({
        number: num
    })
    console.log("but wrong here (previous number): " + this.state.number)

简而言之:使用 setState(function|object nextState[, function callback])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接