首页 文章

React setState / getState和异步

提问于
浏览
6

Why there is no async getState function in React ?

文档告诉我们setState是异步的 . 很好,但这意味着 we can't safely use this.state 我们需要一个异步getState来尊重执行顺序 .

根据我的理解,我们永远不应该使用this.state并使用这样的getState函数:

getState(callback) {
    this.setState((prevState) => {
      callback(prevState) ;
    });
  }
  ...
  this.getState((curState) => {
    // we now can use the current state safely
  }

在我的思维方式中,我在这里缺少什么?为什么React中不存在这样的功能?

-- EDIT --

正如我的一位朋友告诉我的那样,目前尚不清楚,因为我不相信第一个答案,让我们分析一些代码:

simpleFunc() {
    setState({ "counter" : 1 });
    setState({ "counter" : 2 });
    this.state.counter // => no garanty about the value
    getState((curState) => {  // ensure curState.counter is 2 });
}

这个简单的例子显示 we can't use this.state directly in all situations ,因为setState是异步的 .

这是一个可以使用getState的计数器示例:http://codepen.io/Epithor/pen/ZLavWR?editors=0010#0

Short answer: 糟糕的实践,甚至不确定getState给我们当前的

解决方法很简单,但事实上我们可以分解一些函数并使用它们而不关心上下文似乎很有趣,不是吗?

因此,当许多事件以特定顺序发生时,一些事件会改变状态,一些事件会读取状态:如何确定,当事件读取状态时 this.state 读取良好状态,因为所有更改都是异步的?

事实上所有都是关于时间的:

T     : event 1, change state
T+1ms : event 2, change state
T+2ms : event 3, read state
T+3ms : event 4, change state

由于无法预测何时会发生事件1或2的setState, how you could guarantee that event 3 will really read the state set at event 2 ?

Short answer: 事件在JS堆栈中排队,而状态更改在内部React队列中排队 . 在给出手之前,内部反应队列完全取消堆叠 .

3 回答

  • 2

    你绝对可以直接使用 this.state in general . 你永远不应该直接改变状态( this.state.foo = 0 ),而是在你想改变状态时使用 setState .

    通常 setState 看起来像这样:

    this.setState({
        foo: 0
    })
    

    然后你可以安全地使用 this.state.foo 例如在你的 render() 函数中 .

    但是有一点需要注意,由于 setState 的异步性质,您无法保证在调用 setState 之后您可以立即访问 this.state .

    myFunc(baz) {
        this.setState({
            foo: baz + 1
        })
        console.log(this.state.foo) // not guaranteed
    }
    

    更好

    myFunc(baz) {
        const bazOne = baz + 1
        this.setState({
            foo: bazOne
        })
        console.log(bazOne)
    }
    

    或者使用 setState functions第二个参数,用作setState操作完成时执行的回调 . 在该回调中,您将可以访问更新的状态,即 this.state

    this.setState({ foo }, () => { console.log(this.state.foo) });

    见:https://facebook.github.io/react/docs/react-component.html#setstate

  • 13

    setState是异步的,因此您无法立即访问您更改的属性,但是,有些情况下您希望在状态更改后执行操作,在这种情况下您可以执行以下操作:

    ...
    
    this.state = {
      x = 1
    }
    
    ...
    
    this.setState({
      x = 2
    }, () => {
      console.log(this.state.x) // outputs 2
    });
    

    setState函数在排队的tick上调用,因此你可以排队x个setStates,它们将在下一个tick上执行 .

  • 2

    它实际上不是错误/问题,而是架构决策: state 不打算用作简单的属性/变量/存储,它需要在每次调用时更新 . 它使用内部队列,因此如果在渲染之前多次交换状态,它实际上只会使用最终值更新一次,并且在调用 render 方法时,它将包含正确的值 .

    如果您只需要在执行期间或在同一阶段(例如 componentWillReceivePropsshouldComponentUpdate )中运行的方法之间存储/检索信息,您可以像往常一样安全地使用 this.anyProperty

    componentWillReceiveProps() {
      this.value = 'guaranteed';
      return true;
    }
    shouldComponentUpdate() {
      if (this.value === 'guaranteed') {
        console.log('will always return true');
      }
    }
    componentDidUpdate() {
      this.value = ''; //cleanup
    }
    

    在上面的示例中,如果您使用"setState",则无法保证在"shouldComponentUpdate"中始终更新该值,但如果您将其用于其预期目的则无关紧要 . 保证状态更改已被 render 时间刷新,因此它应仅包含呈现阶段使用的信息,而不包含对象的事务/内部数据 . 您可以像往常一样继续使用对象属性 .

相关问题