为什么调用react setState方法不会立即改变状态?

时间:2015-06-11 13:58:26

标签: javascript reactjs react-jsx

我正在阅读Forms文档的部分,并尝试使用此代码来演示onChange用法(JSBIN)。

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

当我更新浏览器中的<input/>值时,console.log回调中的第二个handleChange会打印与第一个value相同的console.log,为什么我无法在this.setState({value: event.target.value})回调范围内看到handleChange的结果?

6 个答案:

答案 0 :(得分:517)

来自React&#39; documentation

  

setState()不会立即改变this.state但会创建一个   待定状态转换。在调用此文件后访问this.state   方法可以返回现有值。没有   保证同步操作setState和电话可能   为获得业绩增长而受到批评。

如果您希望在状态更改发生后执行某项功能,请将其作为回调传递。

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});

答案 1 :(得分:41)

正如React文档中所述,无法保证同步触发setState,因此您的console.log可能会在更新之前返回状态。

Michael Parker提到在setState内传递回调。在状态更改后处理逻辑的另一种方法是通过componentDidUpdate生命周期方法,这是React docs中推荐的方法。

  

通常我们建议使用componentDidUpdate()代替这种逻辑。

当可能连续setState被触发时,这个特别有用,并且您希望在每次状态更改后触发相同的函数。您可以将函数放在setState内,而不是向每个componentDidUpdate添加回调,如果需要,可以在内部使用特定逻辑。

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}

答案 2 :(得分:10)

您可以尝试使用ES7异步/等待。例如,以您的示例为例:

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}

答案 3 :(得分:6)

当心反应生命周期方法!

我工作了几个小时才发现,每getDerivedStateFromProps之后都会调用setState()

答案 4 :(得分:0)

async-await语法非常适合以下内容...

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

答案 5 :(得分:0)

  

简单地放置-this.setState({data:value})是异步的   这意味着它会移出调用堆栈,而只会返回   除非解决了,否则将调用“呼叫堆栈”。

请阅读有关事件循环的详细信息,以了解JS中的异步性质以及更新为什么需要时间-

  

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

因此-

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

,因为更新需要时间。 要实现上述过程-

    this.setState({data:value},function () {
     console.log(this.state.data);
    });