【问题标题】:React setState() guarantees反应 setState() 保证
【发布时间】:2017-08-20 09:48:34
【问题描述】:

在 setState 的文档中是这样说的:

setState() 不会立即改变 this.state 而是创建一个挂起的状态转换。调用此方法后访问 this.state 可能会返回现有值。

不保证 setState 调用的同步操作,调用可能会被批处理以提高性能。

所以我明白你是否有像这样的事件处理程序:

handleClick() {
  this.stuff1();
  this.stuff2();
}

stuff1() {
  this.setState({...});
}

stuff2() {
  doSomethingWithState(this.state);
  this.setState({...});
}

然后在 stuff2 方法中,您可能不会(或者这保证您不会......)看到来自 stuff1 的状态更新。 React 通过向 setState() 提供函数而不是对象,提供了一种“安全地”访问先前状态的方法。但据推测,您可以通过在处理事件时自己跟踪状态并在方法结束时调用 setState() 来解决此问题。因此,也许还有另一个原因选项可以为 setState() 提供函数。如果在调用 handleClick 方法之前可以对状态进行其他更改怎么办?

例如,如果handleClick() 被调用了两次,那么我是否可以保证在第二次调用handleClick() 时看到状态从第一次调用到handleClick() 的变化?还是在调用我的事件处理程序之前,状态可能会变脏?

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    任何时候你有一个从前一个状态派生的状态,如果你不使用回调函数而不是传入一个对象,你可能会遇到它们不同步的问题。在您的最后一个示例中,只有使用该函数才能保证您的安全。如果您依赖this.state,您很容易遇到这样的情况:handleClick 被调用一次,状态转换排队等待稍后解决,您再次调用handleClick,第一次状态更改仍在等待中并且在队列中,因此当您调用 this.state 时,它的可用状态与第一个 handleClick 的可用状态相同,这不是您想要的。

    这将是一个使用回调函数的示例,假设doSomethingWithState 返回更新后的状态对象并且当然是非可变的。

    stuff2() {
      this.setState((state) => {
        const updatedState = doSomethingWithState(state);
        return state;
      })
    }
    

    这是一篇关于使用函数 vs setState 的精彩文章,还包括一个演示问题的 codepen 示例。 https://medium.com/@shopsifter/using-a-function-in-setstate-instead-of-an-object-1f5cfd6e55d1#.gm2t01g70

    【讨论】:

    • 那种看起来很疯狂。如果您有一个文本字段和一个提交按钮怎么办。更改时的文本字段会更新对象中的文本字段,然后提交按钮将其发送到服务器。在您刚刚执行的提交处理程序中:$.post("/url", {value: this.state.value})。你是说它可以读取旧值吗?就像这样做的唯一正确方法是:this.setState({}, () => $.post("/url", {value: this.state.value}))
    • 当提交处理程序只引用状态而不尝试对其进行更新时,我从来没有做过类似的事情。
    • 我认为 DOM 事件发生的情况是事件由所有反应事件侦听器处理,然后状态被刷新。因此,如果您只有一个事件侦听器,那么状态将始终是安全的。如果您有多个事件侦听器,那么如果它们都修改相同的组件状态(?),那么您需要使用 setState 的功能版本。另一方面,对于 ajax、计时器等,没有批处理,每当您调用 setState 时,它​​似乎都会立即触发渲染(不确定状态是否立即更新..)。
    • 如果您跨多个组件处理相同的事件,我有一个令人费解的示例来说明丢失的更新:codepen.io/anon/pen/KWxXzX
    【解决方案2】:

    如果我理解正确,那么答案是否定的,你不能保证,因为 setState 是一个异步操作 - 所以它有点相当于你提到的第一个“问题”。您可以为 setState 方法提供一个回调函数,该回调函数将在 setState 方法完成时触发。然后,在回调范围内,您可以保证当前状态已更新,并且还提供旧状态以进行比较和其他内容....

    【讨论】:

      【解决方案3】:

      您可以按上述方式提供回调。或者由于您希望第一个函数在 handleClick() 中执行,您可以做的是在第一个函数中设置状态后调用第二个函数。即,

      handleClick() {
        this.stuff1();
      }
      
      stuff1() {
        this.setState({...}, 
          () => { 
            this.stuff2(); 
          });
      }
      
      stuff2() {
        doSomethingWithState(this.state);
        this.setState({...});
      }
      

      我认为这将为提出的问题提供解决方案。由于我们不能保证对 setState 的调用的同步操作,因为它是异步操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-12-09
        • 2019-08-27
        • 2021-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多